El proveedor pid permite realizar un seguimiento de cualquier instrucción en un proceso. A diferencia de otros proveedores, los sondeos pid se crean a petición basándose en las descripciones de sondeos que se encuentran en los programas escritos en D. Como resultado, ningún sondeo pid aparece en la salida de dtrace-l hasta que los haya activado.
El modo más sencillo de funcionamiento del proveedor pid es actuar como espacio de usuario análogo al proveedor fbt. El siguiente programa de ejemplo realiza un seguimiento de todas las entradas de funciones y devuelve las que están compuestas de una única función. La variable de macro $1 (el primer operando de la línea de comandos) es el ID de proceso para el proceso que se debe seguir. La variable de macro $2 (el segundo operando de la línea de comandos) es el nombre de la función desde la que se deben seguir todas las llamadas a funciones.
pid$1::$2:entry { self->trace = 1; } pid$1::$2:return /self->trace/ { self->trace = 0; } pid$1:::entry, pid$1:::return /self->trace/ { }
Escriba la secuencia de comandos de ejemplo anterior y guárdela en un archivo que se llame userfunc.d y, a continuación, aplique chmod para que sea ejecutable. Esta secuencia de comandos genera un resultado similar al siguiente ejemplo:
# ./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 ... |
El proveedor pid sólo se puede usar en procesos que ya se estén ejecutando. Puede usar la variable de macro $target (consulte el Capítulo 15Secuencias de comandos), y las opciones dtrace -c y -p para crear y obtener procesos de interés e instrumentarlos usando DTrace. Por ejemplo, la siguiente secuencia de comandos en D se puede usar para determinar la distribución de las llamadas a funciones que un proceso de sujeto concreto realiza a libc:
pid$target:libc.so::entry { @[probefunc] = count(); }
Para determinar la distribución de este tipo de llamadas realizadas mediante el comando date(1), guarde la secuencia de comandos en un archivo llamado libc.d y ejecute el siguiente comando:
# 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 |
Puede usar el proveedor pid para realizar un seguimiento de instrucciones en cualquier función de usuario. A petición, el proveedor pid creará un sondeo para cada instrucción de una función. El nombre de cada sondeo es el desplazamiento de su instrucción correspondiente en la función expresada como un entero hexadecimal. Por ejemplo, para activar un sondeo asociado a la instrucción del desplazamiento 0x1c en la función foo del módulo bar.so en el proceso cuyo PID sea 123, deberá usar el siguiente comando:
# dtrace -n pid123:bar.so:foo:1c |
Para activar todos los sondeos de la función foo, incluido el sondeo para cada instrucción, puede usar el siguiente comando:
# dtrace -n pid123:bar.so:foo: |
Este comando muestra una técnica realmente eficaz para depurar y analizar aplicaciones de usuario. Los errores poco frecuentes pueden ser difíciles de depurar porque pueden ser complicados de reproducir. A menudo, se identifica un error después de que se produzca, por lo que es demasiado tarde para reconstruir la ruta del código. El siguiente ejemplo muestra cómo se combina el proveedor pid con seguimientos especulativos (consulte el Capítulo 13Seguimiento especulativo) para resolver este problema realizando el seguimiento de todas las instrucciones de una función.
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; }
La ejecución de errorpath.d da como resultado una salida similar a la siguiente:
# ./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 |