Guía de seguimiento dinámico de Solaris

Formato de salida

El seguimiento de las llamadas del sistema supone un método eficaz para observar el comportamiento de la mayoría de los procesos de usuario. Si ha utilizado anteriormente la utilidad truss(1) de Solaris como administrador o programador, es probable que ya sepa que se trata de una herramienta muy útil para tenerla a mano en caso de producirse un problema. Si, por el contrario, nunca ha utilizado truss anteriormente, escriba este comando en uno de las shell para probarlo ahora mismo:


$ truss date

Verá un seguimiento con formato de todas las llamadas del sistema ejecutadas por date(1), seguido de una única línea de salida al final. En el siguiente ejemplo, se ha mejorado el programa rw.d mediante la aplicación de formato a la salida para que tenga un aspecto más parecido a truss(1), lo que le permitirá comprender de forma más fácil la salida. Escriba el siguiente programa y guárdelo en un archivo con el nombre trussrw.d :


Ejemplo 1–2 trussrw.d: seguimiento de las llamadas del sistema con el formato de salida truss(1)

syscall::read:entry,
syscall::write:entry
/pid == $1/
{
	printf("%s(%d, 0x%x, %4d)", probefunc, arg0, arg1, arg2);
}

syscall::read:return,
syscall::write:return
/pid == $1/
{
	printf("\t\t = %d\n", arg1);
}

En este ejemplo, la constante 12345 se sustituye por la etiqueta $1 en cada predicado. Esta etiqueta permite especificar el proceso pertinente como argumento en la secuencia de comandos: $1 se sustituye por el valor del primer argumento al compilar la secuencia de comandos. Para ejecutar trussrw.d, utilice las opciones de dtrace, -q y -s, seguidas del Id. de proceso de la shell como argumento final. La opción - q indica que dtrace debería estar en modo silencioso, y suprimir la línea de encabezado y las columnas de CPU e Id. mostradas en los ejemplos anteriores. Por lo tanto, sólo verá como salida los datos de los que realice un seguimiento de forma explícita. Escriba el siguiente comando (sustituyendo 12345 por el Id. del proceso de la shell) y, a continuación, pulse Intro varias veces en la shell especificada:


# dtrace -q -s trussrw.d 12345
	                 = 1
write(2, 0x8089e48,    1)                = 1
read(63, 0x8090a38, 1024)                = 0
read(63, 0x8090a38, 1024)                = 0
write(2, 0x8089e48,   52)                = 52
read(0, 0x8089878,    1)                 = 1
write(2, 0x8089e48,    1)                = 1
read(63, 0x8090a38, 1024)                = 0
read(63, 0x8090a38, 1024)                = 0
write(2, 0x8089e48,   52)                = 52
read(0, 0x8089878,    1)                 = 1
write(2, 0x8089e48,    1)                = 1
read(63, 0x8090a38, 1024)                = 0
read(63, 0x8090a38, 1024)                = 0
write(2, 0x8089e48,   52)                = 52
read(0, 0x8089878,    1)^C
#

Ahora examinemos más detalladamente el programa D y su salida: En primer lugar, una cláusula similar al programa anterior instrumenta cada llamada de la shell en read(2) y write(2). Sin embargo, en este ejemplo, se utiliza la nueva función printf() para realizar un seguimiento de los datos e imprimirlos en un formato específico:

syscall::read:entry,
syscall::write:entry
/pid == $1/
{
	printf("%s(%d, 0x%x, %4d)", probefunc, arg0, arg1, arg2);
}

La función printf() combina la capacidad de realizar un seguimiento de los datos, al igual que con la función trace() utilizada anteriormente, con la capacidad para proporcionar los datos y otro texto adicional en el formato específico que describa. La función printf() indica a DTrace que debe realizar un seguimiento de los datos asociados a cada argumento ubicado detrás del primer argumento y, a continuación, debe aplicar un formato a los resultados mediante las reglas descritas en el primer argumento printf(), conocido como cadena de formato.

La cadena de formato es una cadena normal que contiene una serie de conversiones de formato; cada una de ellas comienza con el carácter % y describe el formato que debe aplicarse al argumento correspondiente. La primera conversión de la cadena de formato se corresponde con el segundo argumento printf(), la segunda conversión con el tercer argumento, y así sucesivamente. Todo el texto que se encuentra entre una conversión y otra se imprime de forma literal. El carácter que se incluye después del carácter de conversión % describe el formato que se utilizará para el argumento correspondiente. A continuación, se muestran los significados de las tres conversiones de formato utilizadas en trussrw.d:

%d

Imprimir el valor correspondiente como entero decimal. 

%s

Imprimir el valor correspondiente como cadena. 

%x

Imprimir el valor correspondiente como entero hexadecimal. 

La función printf() de DTrace funciona del mismo modo que la rutina de biblioteca printf(3C) de C o la utilidad de la shell printf(1). Si no ha utilizado anteriormente la función printf(), los formatos y las opciones se explican detalladamente en el Capítulo 12Formato de salida. Debe leer detenidamente este capítulo, incluso aunque esté familiarizado con la función printf() de otro lenguaje. En D, printf() se proporciona como una función integrada y hay disponibles nuevas conversiones de formato diseñadas específicamente para DTrace.

Para ayudarle a escribir programas correctos, el compilador del lenguaje D valida cada cadena de formato printf() en su lista de argumentos. Intente cambiar probefunc en la cláusula anterior por el entero 123. Si ejecuta el programa modificado, recibirá un mensaje de error en el que se le indica que la conversión de formato de cadena %s no se puede utilizar con un argumento de entero:


# dtrace -q -s trussrw.d
dtrace: failed to compile script trussrw.d: line 4: printf( )
	   argument #2 is incompatible with conversion #1 prototype:
	        conversion: %s
	         prototype: char [] or string (or use stringof)
	          argument: int
#

Si desea imprimir el nombre de la llamada del sistema de lectura o escritura y sus argumentos, utilice la instrucción printf():

printf("%s(%d, 0x%x, %4d)", probefunc, arg0, arg1, arg2);

para realizar un seguimiento del nombre de la función de sondeo actual y los tres primeros argumentos de enteros en la llamada del sistema, disponibles en las variables de DTrace arg0, arg1 y arg2. Para obtener más información sobre los argumentos de sondeos, consulte el Capítulo 3Variables. El primer argumento para read(2) y write(2) es un descriptor de archivo, que se imprime en valores decimales. El segundo argumento es una dirección de memoria intermedia con un formato de valor hexadecimal. El argumento final es el tamaño de memoria intermedia con un formato de valor decimal. El especificador de formato %4d se utiliza para el tercer argumento con el fin de indicar que el valor debe imprimirse mediante la conversión de formato %d con un ancho de campo mínimo de 4 caracteres. Si el entero presenta un ancho inferior a 4 caracteres, printf() insertará espacios en blanco para alinear la salida.

Para imprimir el resultado de la llamada del sistema y completar cada línea de salida, utilice la siguiente cláusula:

syscall::read:return,
syscall::write:return
/pid == $1/
{
	printf("\t\t = %d\n", arg1);
}

Tenga en cuenta que el proveedor syscall publica también un sondeo con el nombre return para cada llamada del sistema, además de entry. La variable arg1 de DTrace para los sondeos return de syscall evalúa en el valor de retorno de la llamada del sistema. Este valor de retorno presenta un formato de número entero decimal. Las secuencias de caracteres que comienzan por barras diagonales inversas en la cadena de formato se expanden para insertar un tabulador (\t) y una nueva línea (\n) respectivamente. Estas secuencias de escape le ayudan a imprimir o registrar caracteres difíciles de escribir. D admite el mismo conjunto de secuencias de escape que C, C++ y el lenguaje de programación de Java. Encontrará la lista completa de secuencias de escape en el Capítulo 2Tipos, operadores y expresiones.