Puede utilizar las llamadas afunciones de D como trace() o printf() para invocar dos tipos diferentes de servicios proporcionados por DTrace: las acciones que realizan un seguimiento de los datos o modifican el estado externo de DTrace, y las subrutinas, que sólo afectan al estado interno de DTrace. En este capítulo se definen las acciones y las subrutinas, y se describen su sintaxis y su semántica.
Las acciones permiten que los programas de DTrace interactúen con el sistema fuera de esta aplicación. Las acciones más comunes registran datos en una memoria intermedia de DTrace. Hay otras acciones disponibles como, por ejemplo, detener el proceso actual, emitir una señal específica en el proceso actual o suspender todo el seguimiento. Algunas de estas acciones son destructivas, en el sentido de que modifican el sistema, aunque de una forma bien definida. Las acciones destructivas sólo pueden utilizarse si se han habilitado explícitamente. De forma predeterminada, las acciones de registro de datos realizan esta función en la memoria intermedia principal. Para obtener más información sobre la memoria intermedia principal y las directivas de memoria intermedia, consulte el Capítulo 11Memorias intermedias y almacenamiento en memoria intermedia.
Una cláusula puede contener una serie de acciones y manipulaciones de variables. Si una cláusula se deja vacía, se lleva a cabo la acción predeterminada. La acción predeterminada consiste en realizar un seguimiento del identificador de sondeo habilitado (EPID) en la memoria intermedia principal. EPID identifica cuándo se ha habilitado un determinado sondeo con un predicado y acciones específicas. Desde EPID, los consumidores de DTrace pueden determinar el sondeo que ha inducido la acción. De hecho, cuando se realiza un seguimiento de cualquier dato, éste debe ir acompañado de EPID para que el consumidor pueda reconocer los datos. Por lo tanto, la acción predetermina consiste únicamente en realizar un seguimiento de EPID.
El uso de la acción predeterminada facilita la utilización de dtrace(1M). Por ejemplo, el siguiente comando de ejemplo habilita todos los sondeos en el módulo de programación de timeshare TS con la acción predeterminada:
# dtrace -m TS |
Es posible que el comando anterior genere una salida similar a la siguiente:
# dtrace -m TS dtrace: description 'TS' matched 80 probes CPU ID FUNCTION:NAME 0 12077 ts_trapret:entry 0 12078 ts_trapret:return 0 12069 ts_sleep:entry 0 12070 ts_sleep:return 0 12033 ts_setrun:entry 0 12034 ts_setrun:return 0 12081 ts_wakeup:entry 0 12082 ts_wakeup:return 0 12069 ts_sleep:entry 0 12070 ts_sleep:return 0 12033 ts_setrun:entry 0 12034 ts_setrun:return 0 12069 ts_sleep:entry 0 12070 ts_sleep:return 0 12033 ts_setrun:entry 0 12034 ts_setrun:return 0 12069 ts_sleep:entry 0 12070 ts_sleep:return 0 12023 ts_update:entry 0 12079 ts_update_list:entry 0 12080 ts_update_list:return 0 12079 ts_update_list:entry ... |
Las acciones de registro de datos son las acciones principales de DTrace. Cada una de estas acciones registra datos de forma predeterminada en la memoria intermedia principal, aunque también es posible que se utilicen para registrar datos en memorias intermedias especulativas. Consulte el Capítulo 11Memorias intermedias y almacenamiento en memoria intermedia para obtener más información sobre la memoria intermedia principal. Consulte el Capítulo 13Seguimiento especulativo para obtener más información sobre las memorias intermedias especulativas. Las descripciones incluidas en esta sección sólo hacen referencia a la memoria intermedia dirigida, lo que indica que los datos se registran en la memoria intermedia principal o en una memoria intermedia especulativa si la acción sigue una especulación().
void trace(expression)
La acción más básica es trace(), que utiliza una expresión del lenguaje D como argumento y realiza un seguimiento del resultado en la memoria intermedia dirigida. Las siguientes instrucciones son ejemplos de acciones trace():
trace(execname); trace(curlwpsinfo->pr_pri); trace(timestamp / 1000); trace(`lbolt); trace("somehow managed to get here");
void tracemem(address, size_t nbytes)
La acción tracemem() utiliza una expresión del lenguaje D como primer argumento, address, y una constante como segundo argumento, nbytes. tracemem() copia la memoria de la dirección especificada por addr en la memoria intermedia dirigida para la longitud especificada por nbytes.
void printf(string format, ...)
Al igual que trace(), la acción printf() realiza un seguimiento de las expresiones del lenguaje D. Sin embargo, printf() acepta un formato del estilo printf(3C) más elaborado. Al igual que printf(3C), los parámetros están formados por una cadena format seguida de un número variable de argumentos. De forma predeterminada, se realiza un seguimiento de los argumentos en la memoria intermedia dirigida. Más adelante, se da formato a los argumentos para la salida mediante dtrace(1M) en función de la cadena de formato especificada. Por ejemplo, los dos primeros ejemplos de trace() de trace() pueden combinarse para formar una única acción printf():
printf("execname is %s; priority is %d", execname, curlwpsinfo->pr_pri);
Para obtener más información sobre printf(), consulte el Capítulo 12Formato de salida.
void printa(aggregation) void printa(string format, aggregation)
La acción printa() permite mostrar y dar formato a las adiciones. Consulte el Capítulo 9Adiciones para obtener más información sobre las adiciones. Si no se especifica ninguna cadenaformat, printa() sólo realiza un seguimiento de una directiva en el consumidor de DTrace que indica que la adición especificada debería procesarse y mostrarse utilizando el formato predeterminado. Si, por el contrario, se especifica una cadena format, se le dará formato a la adición de la forma en la que se especifique. Consulte el Capítulo 12Formato de salida para obtener una descripción más detallada de la cadena de formato printa().
printa() sólo realiza el seguimiento a una directiva que indica que el consumidor de DTrace debe procesar la adición. No procesa la adición en el núcleo. Por lo tanto, el tiempo entre el seguimiento de la directiva printa() y el procesamiento real de la directiva depende de los factores que afecten al procesamiento de la memoria intermedia. Ente estos factores, se incluyen la velocidad de adición y la directiva de almacenamiento en la memoria intermedia, y si esta directiva es switching, la velocidad a la que se conmutan las memorias intermedias. Consulte el Capítulo 9Adiciones y el Capítulo 11Memorias intermedias y almacenamiento en memoria intermedia para obtener descripciones detalladas de estos factores.
void stack(int nframes) void stack(void)
La acción stack() registra el seguimiento de la pila del núcleo en la memoria intermedia dirigida. La pila del núcleo tendrá una profundidad de nframes. Si no se especifica el valor de nframes, el número de marcos de pila registrados será el número especificado por la opción stackframes. Por ejemplo:
# dtrace -n uiomove:entry'{stack()}' CPU ID FUNCTION:NAME 0 9153 uiomove:entry genunix`fop_write+0x1b namefs`nm_write+0x1d genunix`fop_write+0x1b genunix`write+0x1f7 0 9153 uiomove:entry genunix`fop_read+0x1b genunix`read+0x1d4 0 9153 uiomove:entry genunix`strread+0x394 specfs`spec_read+0x65 genunix`fop_read+0x1b genunix`read+0x1d4 ... |
La acción stack() es un poco diferente de las otras acciones, ya que puede utilizarse como clave en una adición:
# dtrace -n kmem_alloc:entry'{@[stack()] = count()}' dtrace: description 'kmem_alloc:entry' matched 1 probe ^C rpcmod`endpnt_get+0x47c rpcmod`clnt_clts_kcallit_addr+0x26f rpcmod`clnt_clts_kcallit+0x22 nfs`rfscall+0x350 nfs`rfs2call+0x60 nfs`nfs_getattr_otw+0x9e nfs`nfsgetattr+0x26 nfs`nfs_getattr+0xb8 genunix`fop_getattr+0x18 genunix`cstat64+0x30 genunix`cstatat64+0x4a genunix`lstat64+0x1c 1 genunix`vfs_rlock_wait+0xc genunix`lookuppnvp+0x19d genunix`lookuppnat+0xe7 genunix`lookupnameat+0x87 genunix`lookupname+0x19 genunix`chdir+0x18 1 rpcmod`endpnt_get+0x6b1 rpcmod`clnt_clts_kcallit_addr+0x26f rpcmod`clnt_clts_kcallit+0x22 nfs`rfscall+0x350 nfs`rfs2call+0x60 nfs`nfs_getattr_otw+0x9e nfs`nfsgetattr+0x26 nfs`nfs_getattr+0xb8 genunix`fop_getattr+0x18 genunix`cstat64+0x30 genunix`cstatat64+0x4a genunix`lstat64+0x1c 1 ... |
void ustack(int nframes, int strsize) void ustack(int nframes) void ustack(void)
La acción ustack() registra un seguimiento de la pila del usuario en la memoria intermedia dirigida. La pila del usuario tendrá una profundidad de nframes. Si no se especifica el valor de nframes, el número de marcos de pila registrados será el número especificado por la opción ustackframes. Aunque ustack() puede determinar la dirección de los marcos de llamada cuando se activa el sondeo, los marcos de pila no se convertirán en símbolos hasta que el consumidor de DTrace no procese la acción ustack() a nivel de usuario. Si se especifican strsize y un valor diferente a cero, ustack() asignará la cantidad especificada de espacio de cadena y la utilizará para convertir las direcciones en símbolos directamente desde el núcleo. Esta traducción directa de símbolos de usuario está sólo disponible actualmente para la versión 1.5 y superior de la Máquina virtual de Java. La función de traducción de direcciones en símbolos de Java anota las pilas de usuarios que contienen marcos de Java con la clase de Java y el nombre del método. Si no es posible traducir esos marcos, aparecerán sólo como direcciones hexadecimales.
El siguiente ejemplo realiza un seguimiento de una pila sin espacio de cadena y, por lo tanto, sin traducción de direcciones en símbolos de Java:
# dtrace -n syscall::write:entry'/pid == $target/{ustack(50, 0); exit(0)}' -c "java -version" dtrace: description 'syscall::write:entry' matched 1 probe java version "1.5.0-beta3" Java(TM) 2 Runtime Environment, Standard Edition (build 1.5.0-beta3-b58) Java HotSpot(TM) Client VM (build 1.5.0-beta3-b58, mixed mode) dtrace: pid 5312 has exited CPU ID FUNCTION:NAME 0 35 write:entry libc.so.1`_write+0x15 libjvm.so`__1cDhpiFwrite6FipkvI_I_+0xa8 libjvm.so`JVM_Write+0x2f d0c5c946 libjava.so`Java_java_io_FileOutputStream_writeBytes+0x2c cb007fcd cb002a7b cb002a7b cb002a7b cb002a7b cb002a7b cb002a7b cb002a7b cb002a7b cb002a7b cb002a7b cb002a7b cb002a7b cb002a7b cb000152 libjvm.so`__1cJJavaCallsLcall_helper6FpnJJavaValue_ pnMmethodHandle_pnRJavaCallArguments_ pnGThread__v_+0x187 libjvm.so`__1cCosUos_exception_wrapper6FpFpnJJavaValue_ pnMmethodHandle_pnRJavaCallArguments_ pnGThread__v2468_v_+0x14 libjvm.so`__1cJJavaCallsEcall6FpnJJavaValue_nMmethodHandle_ pnRJavaCallArguments_pnGThread __v_+0x28 libjvm.so`__1cRjni_invoke_static6FpnHJNIEnv__pnJJavaValue_ pnI_jobject_nLJNICallType_pnK_jmethodID_pnSJNI_ ArgumentPusher_pnGThread__v_+0x180 libjvm.so`jni_CallStaticVoidMethod+0x10f java`main+0x53d |
Tenga en cuenta que los marcos de pila de C y C++ de la Máquina virtual de Java se presentan de forma simbólica mediante nombres de símbolos "corruptos" de C++ y los marcos de pila de Java se presentan únicamente como direcciones hexadecimales. En el siguiente ejemplo, se muestra una llamada a ustack() con un espacio de cadena diferente a cero.
# dtrace -n syscall::write:entry'/pid == $target/{ustack(50, 500); exit(0)}' -c "java -version" dtrace: description 'syscall::write:entry' matched 1 probe java version "1.5.0-beta3" Java(TM) 2 Runtime Environment, Standard Edition (build 1.5.0-beta3-b58) Java HotSpot(TM) Client VM (build 1.5.0-beta3-b58, mixed mode) dtrace: pid 5308 has exited CPU ID FUNCTION:NAME 0 35 write:entry libc.so.1`_write+0x15 libjvm.so`__1cDhpiFwrite6FipkvI_I_+0xa8 libjvm.so`JVM_Write+0x2f d0c5c946 libjava.so`Java_java_io_FileOutputStream_writeBytes+0x2c java/io/FileOutputStream.writeBytes java/io/FileOutputStream.write java/io/BufferedOutputStream.flushBuffer java/io/BufferedOutputStream.flush java/io/PrintStream.write sun/nio/cs/StreamEncoder$CharsetSE.writeBytes sun/nio/cs/StreamEncoder$CharsetSE.implFlushBuffer sun/nio/cs/StreamEncoder.flushBuffer java/io/OutputStreamWriter.flushBuffer java/io/PrintStream.write java/io/PrintStream.print java/io/PrintStream.println sun/misc/Version.print sun/misc/Version.print StubRoutines (1) libjvm.so`__1cJJavaCallsLcall_helper6FpnJJavaValue_ pnMmethodHandle_pnRJavaCallArguments_pnGThread __v_+0x187 libjvm.so`__1cCosUos_exception_wrapper6FpFpnJJavaValue_ pnMmethodHandle_pnRJavaCallArguments_pnGThread __v2468_v_+0x14 libjvm.so`__1cJJavaCallsEcall6FpnJJavaValue_nMmethodHandle _pnRJavaCallArguments_pnGThread__v_+0x28 libjvm.so`__1cRjni_invoke_static6FpnHJNIEnv__pnJJavaValue_pnI _jobject_nLJNICallType_pnK_jmethodID_pnSJNI _ArgumentPusher_pnGThread__v_+0x180 libjvm.so`jni_CallStaticVoidMethod+0x10f java`main+0x53d 8051b9a |
La salida del ejemplo anterior muestra la información de marcos de pila simbólicos para los marcos de pila de Java. Aún hay varios marcos hexadecimales en esta salida, ya que algunas funciones son estáticas y no tienen entradas en la tabla de símbolos de la aplicación. Por lo tanto, no se puede realizar la traducción para estos marcos.
La traducción en símbolos de ustack() para los marcos que no son de Java se produce después de registrar los datos de la pila. Por lo tanto, es posible que se cierre el proceso de usuario antes de que se realice la traducción en símbolos, por lo que la traducción de los marcos de pila no se podría realizar. Si el proceso de usuario se cierra antes de que se realice la traducción en símbolos, dtrace emitirá un mensaje de advertencia, seguido de los marcos de pila hexadecimales, como se muestra en el siguiente ejemplo:
dtrace: failed to grab process 100941: no such process c7b834d4 c7bca85d c7bca1a4 c7bd4374 c7bc2628 8047efc |
Las técnicas para solucionar este problema se describen en el Capítulo 33Seguimiento de procesos de usuario.
Por último, dado que los comandos del depurador de DTrace postmortem no pueden realizar la traducción de los marcos, el uso de ustack() con una directiva de memoria intermedia ring siempre generará datos de ustack() sin formato.
El siguiente programa D muestra un ejemplo de ustack() en el que se deja sin especificar strsize:
syscall::brk:entry /execname == $$1/ { @[ustack(40)] = count(); }
Para ejecutar este ejemplo en el explorador Web de Netscape, .netscape.bin en las instalaciones predeterminadas de Solaris, utilice el siguiente comando:
# dtrace -s brk.d .netscape.bin dtrace: description 'syscall::brk:entry' matched 1 probe ^C libc.so.1`_brk_unlocked+0xc 88143f6 88146cd .netscape.bin`unlocked_malloc+0x3e .netscape.bin`unlocked_calloc+0x22 .netscape.bin`calloc+0x26 .netscape.bin`_IMGCB_NewPixmap+0x149 .netscape.bin`il_size+0x2f7 .netscape.bin`il_jpeg_write+0xde 8440c19 .netscape.bin`il_first_write+0x16b 8394670 83928e5 .netscape.bin`NET_ProcessHTTP+0xa6 .netscape.bin`NET_ProcessNet+0x49a 827b323 libXt.so.4`XtAppProcessEvent+0x38f .netscape.bin`fe_EventLoop+0x190 .netscape.bin`main+0x1875 1 libc.so.1`_brk_unlocked+0xc libc.so.1`sbrk+0x29 88143df 88146cd .netscape.bin`unlocked_malloc+0x3e .netscape.bin`unlocked_calloc+0x22 .netscape.bin`calloc+0x26 .netscape.bin`_IMGCB_NewPixmap+0x149 .netscape.bin`il_size+0x2f7 .netscape.bin`il_jpeg_write+0xde 8440c19 .netscape.bin`il_first_write+0x16b 8394670 83928e5 .netscape.bin`NET_ProcessHTTP+0xa6 .netscape.bin`NET_ProcessNet+0x49a 827b323 libXt.so.4`XtAppProcessEvent+0x38f .netscape.bin`fe_EventLoop+0x190 .netscape.bin`main+0x1875 1 ... |
void jstack(int nframes, int strsize) void jstack(int nframes) void jstack(void)
jstack() es un alias de ustack() que utiliza la opción jstackframes para el valor de número de marcos de pila especificado y para el valor de tamaño de espacio de cadena especificado por la opción jstackstrsize. jstacksize se establece de forma predeterminada en un valor diferente a cero. Como resultado, el uso de jstack() generará una pila con una traducción de marcos de Java.
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 |
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.
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.
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.
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.
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.
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().
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.
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 # |
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().
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);}' |
En esta sección, se describen las acciones que no son de registro de datos ni destructivas.
Las acciones asociadas al seguimiento especulativo son speculate(), commit() y discard(). Estas acciones se describen en el Capítulo 13Seguimiento especulativo.
void exit(int status)
La acción exit() se utiliza para detener de forma inmediata el seguimiento e informar al consumidor de DTrace de que debería dejar de realizar el seguimiento, realizar el procesamiento final y llamar a exit(3C) con el estado especificado. Dado que exit() devuelve un estado a nivel de usuario, se trata de una acción de registro de datos. Sin embargo, a diferencia de otras acciones de almacenamiento de datos, no se puede realizar un seguimiento especulativo de exit(). exit() provocará que el consumidor de DTrace detenga el proceso independientemente de la directiva de memoria intermedia. Como exit() es una acción de registro de datos, puede descartarse.
Al llamar a exit(), sólo se completarán las acciones de DTrace en curso en otras CPU. No tendrá lugar ninguna nueva acción en ninguna CPU. La única excepción a esta regla es el procesamiento del sondeo END, al que se llamará una vez que el consumidor de DTrace haya procesado la acción exit() e indicado que debe detenerse el seguimiento.
Las subrutinas se diferencias de las acciones en que, normalmente, sólo afectan al estado interno de DTrace. Por lo tanto, no hay subrutinas destructivas y, además, éstas nunca realizarán un seguimiento de los datos en las memorias intermedias. Muchas subrutinas tienen elementos análogos en las interfaces de la Sección 9F o la Sección 3C. Consulte Intro(9F) e Intro(3) para obtener más información sobre las subrutinas correspondientes.
void *alloca(size_t size)
alloca() asigna el número de bytes especificado en size fuera del espacio temporal y devuelve un puntero a la memoria asignada. Se garantiza que el puntero devuelto presente una alineación de 8 bytes. El espacio temporal sólo es válido durante la duración de una cláusula. La memoria asignada con alloca() se desasignará cuando se complete la cláusula. Si no hay suficiente espacio temporal disponible, no se asignará ninguna memoria y se generará un error.
string basename(char *str)
basename() es un elemento análogo del lenguaje D para basename(1). Esta subrutina crea una cadena formada por una copia de la cadena especificada, aunque sin un prefijo terminado en /. La cadena devuelta se asigna fuera de la memoria temporal y, por lo tanto, sólo es válida durante la duración de la cláusula. Si no hay suficiente espacio temporal disponible, basename no se ejecuta y se genera un error.
void bcopy(void *src, void *dest, size_t size)
bcopy() copia el número de bytes especificado en size de la memoria a la que señala src a la memoria a la que señala dest. Toda la memoria de origen debe encontrarse fuera de la memoria temporal, y toda la memoria de destino debe encontrarse dentro. Si no se cumplen estas condiciones, no se realizará la copia y se generará un error.
string cleanpath(char *str)
cleanpath() crea una cadena formada por una copia de la ruta que indica str, aunque con determinados elementos redundantes eliminados. En concreto, se eliminan los elementos "/./" de la ruta y se contraen los elementos "/../". Los elementos /../ de la ruta se contraen independientemente de los vínculos simbólicos. Por lo tanto, es posible que cleanpath() pueda utilizar una ruta válida y devolver una ruta no válida más corta.
Por ejemplo, si str es " /foo/../bar" y /foo es un vínculo simbólico a /net/foo/export, cleanpath() devolverá "/bar", aunque bar sólo puede estar en /net/foo y no en /. Esta limitación se debe al hecho de que la llamada a cleanpath() se realiza en el contexto de una activación del sondeo, en el que no se puede realizar la resolución completa de vínculos simbólicos ni utilizar nombres arbitrarios. La cadena devuelta se asigna fuera de la memoria temporal y, por lo tanto, sólo es válida durante la duración de la cláusula. Si no hay suficiente espacio temporal disponible, cleanpath no se ejecuta y se genera un error.
void *copyin(uintptr_t addr, size_t size)
copyin() copia el tamaño especificado en bytes de la dirección de usuario especificada en la memoria intermedia temporal de DTrace y devuelve la dirección de esta memoria intermedia. La dirección de usuario se interpreta como una dirección en el espacio del proceso asociado al subproceso actual. Se garantiza que el puntero de memoria intermedia resultante presente una alineación de 8 bytes. La dirección en cuestión debe corresponderse con la página fallida en el proceso actual. Si la dirección no se corresponde con la página fallida o si no hay suficiente espacio temporal disponible, se devuelve el valor NULL y se genera un error. Consulte el Capítulo 33Seguimiento de procesos de usuario para conocer las técnicas que permiten reducir las probabilidades de que se produzcan errores de copyin.
string copyinstr(uintptr_t addr)
copyinstr() copia la cadena de C finalizada con un valor "null" de la dirección de usuario especificada en la memoria intermedia temporal de DTrace y devuelve la dirección de esta memoria intermedia. La dirección de usuario se interpreta como una dirección en el espacio del proceso asociado al subproceso actual. 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 información. Al igual que en copyin, la dirección especificada debe corresponderse con una página fallida en el proceso actual. Si la dirección no se corresponde con la página fallida o si no hay suficiente espacio temporal disponible, se devuelve el valor NULL y se genera un error. Consulte el Capítulo 33Seguimiento de procesos de usuario para conocer las técnicas que permiten reducir las probabilidades de que se produzcan errores de copyinstr.
void copyinto(uintptr_t addr, size_t size, void *dest)
copyinto() copia el tamaño especificado en bytes de la dirección de usuario especificada en la memoria intermedia temporal de DTrace indicado por dest. La dirección de usuario se interpreta como una dirección en el espacio del proceso asociado al subproceso actual. La dirección en cuestión debe corresponderse con la página fallida en el proceso actual. Si la dirección no se corresponde con una página fallida o si la memoria de destino se encuentra fuera del espacio temporal, no se realiza la copia y se genera un error. Consulte el Capítulo 33Seguimiento de procesos de usuario para conocer las técnicas que permiten reducir las probabilidades de que se produzcan errores de copyinto.
string dirname(char *str)
dirname() es un elemento análogo del lenguaje D para dirname(1). Esta subrutina crea una cadena formada por todos los niveles del nombre de ruta especificado por str, excepto el último. La cadena devuelta se asigna fuera de la memoria temporal y, por lo tanto, sólo es válida durante la duración de la cláusula. Si no hay suficiente espacio temporal disponible, dirname no se ejecuta y se genera un error.
size_t msgdsize(mblk_t *mp)
msgdsize() devuelve el número de bytes del mensaje de datos al que señala mp. Consulte msgdsize(9F) para obtener más información. msgdsize() sólo incluye bloques de datos del tipo M_DATA en el recuento.
size_t msgsize(mblk_t *mp)
msgsize() devuelve el número de bytes del mensaje al que señala mp. A diferencia de msgdsize(), que devuelve sólo el número de bytes de datos, msgsize () devuelve el número total de bytes del mensaje.
int mutex_owned(kmutex_t *mutex)
mutex_owned() es una implementación de mutex_owned(9F). mutex_owned() devuelve un valor distinto a cero si el subproceso de llamada contiene actualmente la exclusión mutua del núcleo especificada o el valor cero si la exclusión mutua adaptable especificada no tiene actualmente ningún propietario.
kthread_t *mutex_owner(kmutex_t *mutex)
mutex_owner() el puntero de subproceso del propietario de la exclusión mutua del núcleo adaptable especificada. mutex_owner() devuelve el valor NULL si la exclusión mutua adaptable especificada no tiene actualmente ningún propietario o si la exclusión mutua especificada es circular. Consulte mutex_owned(9F).
int mutex_type_adaptive(kmutex_t *mutex)
mutex_type_adaptive() devuelve un valor distinto a cero si la exclusión mutua del núcleo especificada es del tipo MUTEX_ADAPTIVE o el valor cero si no es de ese tipo. Las exclusiones mutuas son adaptables si cumplen una o varias de las siguientes condiciones:
La exclusión mutua se ha declarado de forma estática.
La exclusión mutua se crea con la cookie de bloqueo de interrupción NULL.
La exclusión mutua se crea con una cookie de bloqueo de interrupción que no se corresponde con una interrupción de alto nivel.
Consulte mutex_init(9F) para obtener más información sobre las exclusiones mutuas. La mayoría de las exclusiones mutuas del núcleo de Solaris son adaptables.
int progenyof(pid_t pid)
progenyof() devuelve un valor distinto a cero si el proceso de llamada (el proceso asociado al subproceso que está activando actualmente el sondeo coincidente) se encuentra entre la progenie del Id. de proceso especificado.
int rand(void)
rand() devuelve un entero seudoaleatorio. El número devuelto es un número débil pseudoaleatorio que no debe utilizarse para ninguna aplicación criptográfica.
int rw_iswriter(krwlock_t *rwlock)
rw_iswriter() devuelve un valor distinto a cero si un escritor mantiene o desea realizar un bloqueo de lector-escritor. Si sólo los lectores mantienen el bloqueo y no hay ningún escritor bloqueado, o si no se realiza ningún bloqueo, rw_iswriter() devuelve el valor cero. Consulte rw_init(9F).
int rw_write_held(krwlock_t *rwlock)
rw_write_held() devuelve un valor distinto a cero si un escritor mantiene actualmente un bloqueo de escritor-lector. Si sólo los lectores mantienen el bloqueo o si no se realiza ningún bloqueo, rw_write_held() devuelve el valor cero. Consulte rw_init(9F).
int speculation(void)
speculation() reserva una memoria intermedia de seguimiento especulativo para su uso con speculate() y devuelve un identificador para esta memoria intermedia. Consulte el Capítulo 13Seguimiento especulativo para obtener más información.
string strjoin(char *str1, char *str2)
strjoin() crea una cadena formada por str1 en combinación con str2. La cadena devuelta se asigna fuera de la memoria temporal y, por lo tanto, sólo es válida durante la duración de la cláusula. Si no hay suficiente espacio temporal disponible, strjoin no se ejecuta y se genera un error.
size_t strlen(string str)
strlen() devuelve la longitud de la cadena especificada en bytes, a excepción del byte nulo final.