GNU/Linux >> Tutoriales Linux >  >> Linux

Comprender las llamadas al sistema en Linux con strace

Una llamada al sistema es una forma programática en la que un programa solicita un servicio del kernel y strace es una poderosa herramienta que le permite rastrear la delgada capa entre los procesos de usuario y el kernel de Linux.

Para comprender cómo funciona un sistema operativo, primero debe comprender cómo funcionan las llamadas al sistema. Una de las funciones principales de un sistema operativo es proporcionar abstracciones a los programas de usuario.

Un sistema operativo se puede dividir aproximadamente en dos modos:

  • Modo de núcleo: Un modo privilegiado y poderoso utilizado por el kernel del sistema operativo
  • Modo de usuario: Dónde se ejecutan la mayoría de las aplicaciones de usuario

Los usuarios trabajan principalmente con utilidades de línea de comandos e interfaces gráficas de usuario (GUI) para realizar las tareas diarias. Las llamadas al sistema funcionan silenciosamente en segundo plano, interactuando con el núcleo para realizar el trabajo.

Más recursos de Linux

  • Hoja de trucos de los comandos de Linux
  • Hoja de trucos de comandos avanzados de Linux
  • Curso en línea gratuito:Descripción general técnica de RHEL
  • Hoja de trucos de red de Linux
  • Hoja de trucos de SELinux
  • Hoja de trucos de los comandos comunes de Linux
  • ¿Qué son los contenedores de Linux?
  • Nuestros últimos artículos sobre Linux

Las llamadas al sistema son muy similares a las llamadas a funciones, lo que significa que aceptan y funcionan con argumentos y valores devueltos. La única diferencia es que las llamadas al sistema ingresan a un núcleo, mientras que las llamadas a funciones no lo hacen. El cambio del espacio del usuario al espacio del núcleo se realiza mediante un mecanismo de trampa especial.

La mayor parte de esto está oculto para el usuario mediante el uso de bibliotecas del sistema (también conocido como glibc en sistemas Linux). Aunque las llamadas al sistema son de naturaleza genérica, la mecánica de emitir una llamada al sistema depende en gran medida de la máquina.

Este artículo explora algunos ejemplos prácticos usando algunos comandos generales y analizando las llamadas al sistema hechas por cada comando usando strace . Estos ejemplos usan Red Hat Enterprise Linux, pero los comandos deberían funcionar igual en otras distribuciones de Linux:

[root@sandbox ~]# cat /etc/redhat-release 
Red Hat Enterprise Linux Server release 7.7 (Maipo)
[root@sandbox ~]#
[root@sandbox ~]# uname -r
3.10.0-1062.el7.x86_64
[root@sandbox ~]#

Primero, asegúrese de que las herramientas necesarias estén instaladas en su sistema. Puedes verificar si strace se instala usando el comando RPM a continuación; si es así, puede comprobar el strace número de versión de la utilidad mediante -V opción:

[root@sandbox ~]# rpm -qa | grep -i strace
strace-4.12-9.el7.x86_64
[root@sandbox ~]#
[root@sandbox ~]# strace -V
strace -- version 4.12
[root@sandbox ~]#

Si eso no funciona, instale strace ejecutando:

yum install strace

A los efectos de este ejemplo, cree un directorio de prueba dentro de /tmp y crea dos archivos usando el toque comando usando:

[root@sandbox ~]# cd /tmp/
[root@sandbox tmp]#
[root@sandbox tmp]# mkdir testdir
[root@sandbox tmp]#
[root@sandbox tmp]# touch testdir/file1
[root@sandbox tmp]# touch testdir/file2
[root@sandbox tmp]#

(Usé el /tmp porque todo el mundo tiene acceso a él, pero puede elegir otro directorio si lo prefiere).

Verifique que los archivos se crearon usando ls comando en el testdir directorio:

[root@sandbox tmp]# ls testdir/
file1  file2
[root@sandbox tmp]#

Probablemente utilice el ls comando todos los días sin darse cuenta de que las llamadas al sistema están funcionando debajo de él. Hay abstracción en juego aquí; así es como funciona este comando:

Command-line utility -> Invokes functions from system libraries (glibc) -> Invokes system calls

Los ls El comando llama internamente a funciones de las bibliotecas del sistema (también conocido como glibc ) en Linux. Estas bibliotecas invocan las llamadas al sistema que hacen la mayor parte del trabajo.

Si desea saber qué funciones se llamaron desde el glibc biblioteca, use el ltrace comando seguido del ls testdir/ regular comando:

ltrace ls testdir/

Si ltrace no está instalado, instálelo ingresando:

yum install ltrace

Un montón de resultados se descargarán en la pantalla; no te preocupes por eso, simplemente sígueme. Algunas de las funciones de biblioteca importantes de la salida de ltrace Los comandos que son relevantes para este ejemplo incluyen:

opendir("testdir/")                                  = { 3 }
readdir({ 3 })                                       = { 101879119, "." }
readdir({ 3 })                                       = { 134, ".." }
readdir({ 3 })                                       = { 101879120, "file1" }
strlen("file1")                                      = 5
memcpy(0x1665be0, "file1\0", 6)                      = 0x1665be0
readdir({ 3 })                                       = { 101879122, "file2" }
strlen("file2")                                      = 5
memcpy(0x166dcb0, "file2\0", 6)                      = 0x166dcb0
readdir({ 3 })                                       = nil
closedir({ 3 })                      

Al mirar el resultado anterior, probablemente pueda entender lo que está sucediendo. Un directorio llamado testdir está siendo abierto por opendir función de biblioteca, seguida de llamadas a readdir función, que está leyendo el contenido del directorio. Al final, hay una llamada al closedir función, que cierra el directorio que se abrió anteriormente. Ignora los otros strlen y memcpy funciones por ahora.

Puede ver qué funciones de la biblioteca se están llamando, pero este artículo se centrará en las llamadas del sistema que son invocadas por las funciones de la biblioteca del sistema.

De manera similar a lo anterior, para comprender qué llamadas al sistema se invocan, simplemente coloque strace antes del ls testdir comando, como se muestra a continuación. Una vez más, se descargará un montón de galimatías en su pantalla, que puede seguir aquí:

[root@sandbox tmp]# strace ls testdir/
execve("/usr/bin/ls", ["ls", "testdir/"], [/* 40 vars */]) = 0
brk(NULL)                               = 0x1f12000
<<< truncated strace output >>>
write(1, "file1  file2\n", 13file1  file2
)          = 13
close(1)                                = 0
munmap(0x7fd002c8d000, 4096)            = 0
close(2)                                = 0
exit_group(0)                           = ?
+++ exited with 0 +++
[root@sandbox tmp]#

La salida en la pantalla después de ejecutar strace el comando fue simplemente llamadas al sistema realizadas para ejecutar el ls dominio. Cada llamada al sistema tiene un propósito específico para el sistema operativo y se pueden clasificar en términos generales en las siguientes secciones:

  • Llamadas al sistema de gestión de procesos
  • Llamadas al sistema de administración de archivos
  • Llamadas al sistema de administración de directorios y sistemas de archivos
  • Otras llamadas al sistema

Una forma más fácil de analizar la información volcada en su pantalla es registrar la salida en un archivo usando strace es útil -o bandera. Agregue un nombre de archivo adecuado después de -o marca y ejecuta el comando de nuevo:

[root@sandbox tmp]# strace -o trace.log ls testdir/
file1  file2
[root@sandbox tmp]#

Esta vez, no se descargó ningún resultado en la pantalla:el ls El comando funcionó como se esperaba mostrando los nombres de los archivos y registrando todos los resultados en el archivo trace.log . El archivo tiene casi 100 líneas de contenido solo por un simple ls comando:

[root@sandbox tmp]# ls -l trace.log 
-rw-r--r--. 1 root root 7809 Oct 12 13:52 trace.log
[root@sandbox tmp]#
[root@sandbox tmp]# wc -l trace.log
114 trace.log
[root@sandbox tmp]#

Eche un vistazo a la primera línea del ejemplo de trace.log:

execve("/usr/bin/ls", ["ls", "testdir/"], [/* 40 vars */]) = 0
  • La primera palabra de la línea, execve , es el nombre de una llamada al sistema que se está ejecutando.
  • El texto entre paréntesis son los argumentos proporcionados a la llamada del sistema.
  • El número después de = signo (que es 0 en este caso) es un valor devuelto por execve llamada al sistema.

La salida no parece demasiado intimidante ahora, ¿verdad? Y puedes aplicar la misma lógica para entender otras líneas.

Ahora, limite su atención al único comando que invocó, es decir, ls testdir . Conoce el nombre del directorio utilizado por el comando ls , entonces, ¿por qué no grep? para testdir dentro de su trace.log archivo y ver lo que obtienes? Mire cada línea de los resultados en detalle:

[root@sandbox tmp]# grep testdir trace.log
execve("/usr/bin/ls", ["ls", "testdir/"], [/* 40 vars */]) = 0
stat("testdir/", {st_mode=S_IFDIR|0755, st_size=32, ...}) = 0
openat(AT_FDCWD, "testdir/", O_RDONLY|O_NONBLOCK|O_DIRECTORY|O_CLOEXEC) = 3
[root@sandbox tmp]#

Pensando en el análisis de execve arriba, ¿puede decir qué hace esta llamada al sistema?

execve("/usr/bin/ls", ["ls", "testdir/"], [/* 40 vars */]) = 0

No necesita memorizar todas las llamadas al sistema o lo que hacen, porque puede consultar la documentación cuando lo necesite. ¡Man pages al rescate! Asegúrese de que el siguiente paquete esté instalado antes de ejecutar man comando:

[root@sandbox tmp]# rpm -qa | grep -i man-pages
man-pages-3.53-5.el7.noarch
[root@sandbox tmp]#

Recuerda que debes agregar un 2 entre el hombre comando y el nombre de la llamada al sistema. Si lees hombre La página de manual de usando man man , puede ver que la sección 2 está reservada para llamadas al sistema. Del mismo modo, si necesita información sobre las funciones de la biblioteca, debe agregar un 3 entre hombre y el nombre de la función de biblioteca.

Los siguientes son los números de sección del manual y los tipos de páginas que contienen:

1. Executable programs or shell commands
2. System calls (functions provided by the kernel)
3. Library calls (functions within program libraries)
4. Special files (usually found in /dev)

Ejecute el siguiente hombre Comando con el nombre de la llamada del sistema para ver la documentación de esa llamada del sistema:

man 2 execve

Según el ejecutivo página de manual, esto ejecuta un programa que se pasa en los argumentos (en este caso, eso es ls ). Hay argumentos adicionales que se pueden proporcionar a ls , como testdir en este ejemplo. Por lo tanto, esta llamada al sistema solo ejecuta ls con testdir como argumento:

'execve - execute program'

'DESCRIPTION
       execve()  executes  the  program  pointed to by filename'

La siguiente llamada al sistema, llamada stat , usa el testdir argumento:

stat("testdir/", {st_mode=S_IFDIR|0755, st_size=32, ...}) = 0

Usar estadística hombre 2 para acceder a la documentación. estadística es la llamada al sistema que obtiene el estado de un archivo; recuerde que todo en Linux es un archivo, incluido un directorio.

A continuación, el openat la llamada al sistema abre testdir. Vigila el 3 que se devuelve. Esta es una descripción de archivo, que será utilizada por posteriores llamadas al sistema:

openat(AT_FDCWD, "testdir/", O_RDONLY|O_NONBLOCK|O_DIRECTORY|O_CLOEXEC) = 3

Hasta aquí todo bien. Ahora, abra el trace.log y vaya a la línea que sigue a openat llamada del sistema. Verá los getdents llamada al sistema que se invoca, que hace la mayor parte de lo que se requiere para ejecutar ls testdir dominio. Ahora, grep getdents desde el trace.log archivo:

[root@sandbox tmp]# grep getdents trace.log 
getdents(3, /* 4 entries */, 32768)     = 112
getdents(3, /* 0 entries */, 32768)     = 0
[root@sandbox tmp]#

Los getdents la página de manual lo describe como obtener entradas de directorio , que es lo que quieres hacer. Observe que el argumento para getdents es 3 , que es el descriptor de archivo de openat llamada al sistema anterior.

Ahora que tiene la lista del directorio, necesita una forma de mostrarla en su terminal. Entonces, grep para otra llamada al sistema, escribir , que se usa para escribir en la terminal, en los registros:

[root@sandbox tmp]# grep write trace.log
write(1, "file1  file2\n", 13)          = 13
[root@sandbox tmp]#

En estos argumentos, puede ver los nombres de los archivos que se mostrarán:file1 y archivo2 . En cuanto al primer argumento (1 ), recuerda en Linux que, cuando se ejecuta cualquier proceso, por defecto se abren tres descriptores de archivo para el mismo. Los siguientes son los descriptores de archivo predeterminados:

  • 0 - Entrada estándar
  • 1 - Estándar fuera
  • 2 - Error estándar

Entonces, el escribir la llamada del sistema muestra file1 y archivo2 en la pantalla estándar, que es el terminal, identificado por 1 .

Ahora sabe qué llamadas al sistema hicieron la mayor parte del trabajo para ls testdir/ dominio. Pero, ¿qué pasa con las otras más de 100 llamadas al sistema en trace.log? ¿expediente? El sistema operativo tiene que hacer una gran cantidad de limpieza para ejecutar un proceso, por lo que mucho de lo que ve en el archivo de registro es la inicialización y limpieza del proceso. Leer todo el trace.log archivo e intente entender lo que está sucediendo para que el ls trabajo de mando.

Ahora que sabe cómo analizar las llamadas al sistema para un comando dado, puede usar este conocimiento para otros comandos para comprender qué llamadas al sistema se están ejecutando. straza proporciona muchas banderas de línea de comandos útiles para que sea más fácil para usted, y algunas de ellas se describen a continuación.

De forma predeterminada, strace no incluye toda la información de llamadas al sistema. Sin embargo, tiene un útil -v detallado opción que puede proporcionar información adicional sobre cada llamada al sistema:

strace -v ls testdir

Es una buena práctica usar siempre la -f opción al ejecutar strace dominio. Permite strace para rastrear cualquier proceso secundario creado por el proceso que se está rastreando actualmente:

strace -f ls testdir

Digamos que solo quiere los nombres de las llamadas al sistema, la cantidad de veces que se ejecutaron y el porcentaje de tiempo dedicado a cada llamada al sistema. Puedes usar -c marca para obtener esas estadísticas:

strace -c ls testdir/

Suponga que desea concentrarse en una llamada de sistema específica, como enfocarse en abrir llamadas al sistema e ignorando el resto. Puedes usar la -e indicador seguido del nombre de la llamada al sistema:

[root@sandbox tmp]# strace -e open ls testdir
open("/etc/ld.so.cache", O_RDONLY|O_CLOEXEC) = 3
open("/lib64/libselinux.so.1", O_RDONLY|O_CLOEXEC) = 3
open("/lib64/libcap.so.2", O_RDONLY|O_CLOEXEC) = 3
open("/lib64/libacl.so.1", O_RDONLY|O_CLOEXEC) = 3
open("/lib64/libc.so.6", O_RDONLY|O_CLOEXEC) = 3
open("/lib64/libpcre.so.1", O_RDONLY|O_CLOEXEC) = 3
open("/lib64/libdl.so.2", O_RDONLY|O_CLOEXEC) = 3
open("/lib64/libattr.so.1", O_RDONLY|O_CLOEXEC) = 3
open("/lib64/libpthread.so.0", O_RDONLY|O_CLOEXEC) = 3
open("/usr/lib/locale/locale-archive", O_RDONLY|O_CLOEXEC) = 3
file1  file2
+++ exited with 0 +++
[root@sandbox tmp]#

¿Qué sucede si desea concentrarse en más de una llamada al sistema? No te preocupes, puedes usar el mismo -e indicador de línea de comandos con una coma entre las dos llamadas al sistema. Por ejemplo, para ver el escribir y dentaduras llamadas al sistema:

[root@sandbox tmp]# strace -e write,getdents ls testdir
getdents(3, /* 4 entries */, 32768)     = 112
getdents(3, /* 0 entries */, 32768)     = 0
write(1, "file1  file2\n", 13file1  file2
)          = 13
+++ exited with 0 +++
[root@sandbox tmp]#

Los ejemplos hasta ahora han rastreado explícitamente ejecutar comandos. Pero, ¿qué pasa con los comandos que ya se han ejecutado y están en ejecución? ¿Qué sucede, por ejemplo, si desea rastrear demonios que son solo procesos de ejecución prolongada? Para ello, strace proporciona un -p especial bandera a la que puede proporcionar un ID de proceso.

En lugar de ejecutar un strace en un demonio, toma el ejemplo de un gato comando, que generalmente muestra el contenido de un archivo si proporciona un nombre de archivo como argumento. Si no se da ningún argumento, el gato El comando simplemente espera en una terminal a que el usuario ingrese el texto. Una vez que se ingresa el texto, repite el texto dado hasta que un usuario presiona Ctrl+C para salir.

Corre el gato comando desde una terminal; le mostrará un aviso y simplemente espere allí (recuerde gato todavía se está ejecutando y no ha salido):

[root@sandbox tmp]# cat

Desde otro terminal, encuentre el identificador de proceso (PID) usando el ps comando:

[root@sandbox ~]# ps -ef | grep cat
root      22443  20164  0 14:19 pts/0    00:00:00 cat
root      22482  20300  0 14:20 pts/1    00:00:00 grep --color=auto cat
[root@sandbox ~]#

Ahora, ejecuta strace en el proceso en ejecución con -p bandera y el PID (que encontraste arriba usando ps ). Después de ejecutar strace , la salida indica a qué se adjuntó el proceso junto con el número de PID. Ahora, straza está rastreando las llamadas al sistema realizadas por el gato dominio. La primera llamada al sistema que ve es leer , que está esperando entrada desde 0, o entrada estándar, que es la terminal donde está el gato se ejecutó el comando:

[root@sandbox ~]# strace -p 22443
strace: Process 22443 attached
read(0,

Ahora, regresa a la terminal donde dejaste al gato comando ejecutándose e ingrese algún texto. Ingresé x0x0 para fines de demostración. Fíjate cómo gato simplemente repetí lo que ingresé; por lo tanto, x0x0 aparece dos veces. Ingresé el primero, y el segundo fue el resultado repetido por el gato comando:

[root@sandbox tmp]# cat
x0x0
x0x0

Vuelva a la terminal donde strace estaba unido al gato proceso. Ahora verá dos llamadas al sistema adicionales:la lectura anterior llamada al sistema, que ahora dice x0x0 en la terminal, y otra para escribir , que escribió x0x0 de vuelta a la terminal, y de nuevo una nueva lectura , que está esperando para leer desde la terminal. Tenga en cuenta que la entrada estándar (0 ) y Salida estándar (1 ) están en el mismo terminal:

[root@sandbox ~]# strace -p 22443
strace: Process 22443 attached
read(0, "x0x0\n", 65536)                = 5
write(1, "x0x0\n", 5)                   = 5
read(0,

Imagina lo útil que es esto cuando ejecutas strace contra demonios para ver todo lo que hace en segundo plano. Mata al gato comando presionando Ctrl+C; esto también mata tu strace sesión ya que el proceso ya no se está ejecutando.

Si desea ver una marca de tiempo en todas las llamadas de su sistema, simplemente use -t opción con strace :

[root@sandbox ~]#strace -t ls testdir/

14:24:47 execve("/usr/bin/ls", ["ls", "testdir/"], [/* 40 vars */]) = 0
14:24:47 brk(NULL)                      = 0x1f07000
14:24:47 mmap(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7f2530bc8000
14:24:47 access("/etc/ld.so.preload", R_OK) = -1 ENOENT (No such file or directory)
14:24:47 open("/etc/ld.so.cache", O_RDONLY|O_CLOEXEC) = 3

¿Qué sucede si desea saber el tiempo transcurrido entre las llamadas al sistema? straza tiene una práctica -r comando que muestra el tiempo empleado en ejecutar cada llamada al sistema. Bastante útil, ¿no?

[root@sandbox ~]#strace -r ls testdir/

0.000000 execve("/usr/bin/ls", ["ls", "testdir/"], [/* 40 vars */]) = 0
0.000368 brk(NULL)                 = 0x1966000
0.000073 mmap(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7fb6b1155000
0.000047 access("/etc/ld.so.preload", R_OK) = -1 ENOENT (No such file or directory)
0.000119 open("/etc/ld.so.cache", O_RDONLY|O_CLOEXEC) = 3

Conclusión

La straza La utilidad es muy útil para comprender las llamadas al sistema en Linux. Para obtener más información sobre sus otros indicadores de línea de comandos, consulte las páginas man y la documentación en línea.


Linux
  1. Supervise su sistema Linux en su terminal con procps-ng

  2. Mejore el rendimiento del sistema Linux con noatime

  3. Programación de tareas del sistema con Cron en Linux

  4. Equilibrar la seguridad de Linux con la usabilidad

  5. Howto:programación en C con directorios en Linux

Cómo ver las estadísticas del sistema Linux con Saidar

11 Comando Strace con ejemplo en Linux

Cómo usar el comando Strace de Linux

Comprender los procesos en Linux

Entendiendo Crontab en Linux con ejemplos

¿Qué son las llamadas al sistema Linux y las funciones de biblioteca?