Guía de seguimiento dinámico de Solaris

Proveedor pid

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.

Seguimiento de los límites de la función de usuario

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.


Ejemplo 33–1 userfunc.d: seguimiento de la entrada y devolución de una función de usuario

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

Seguimiento de instrucciones arbitrarias

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.


Ejemplo 33–2 errorpath.d: seguimiento de la ruta de error de una llamada de función de usuario

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