Mejore la calidad del código y evite resultados inesperados aprendiendo a utilizar GNU Debugger para revelar errores no deseados en su código.
La depuración es una habilidad indispensable para programadores e investigadores de seguridad. Tener un buen conocimiento de la depuración le permite comprender un ejecutable en un nivel inferior y detectar cualquier error oculto.
El depurador GNU o GDB es una herramienta de depuración atemporal en la que los programadores han confiado desde hace años. A continuación se explica cómo utilizar GDB en Linux.
Preparación de programas de muestra
Para explorar las características de GDB necesitarás un ejecutable con el que experimentar. Para demostración, ejecutará GDB en un programa de verificación de claves una vez con el código fuente y símbolos de depuración disponibles, una vez sin código fuente, y en un programa simple multiproceso que imprime mensajes en la pantalla, ambos escritos en C y compilados con GCC (GNU C Compilador).
Puede usar cualquier otro compilador de C pero asegúrese de no eliminar el binario.
Lo más probable es que esté ejecutando GDB en sus propios programas. Así que asegúrese de compilarlos con el -gramo marca con gcc para habilitar los símbolos de depuración.
Sin los símbolos de depuración presentes y con un binario muy eliminado, tendrás que depurar el desmontaje del programa. Esto requerirá que tengas un buen conocimiento del lenguaje ensamblador y cómo funciona la asignación de memoria en Linux para comprender los datos en la pila y los registros.
Ejecutando un programa en GDB
Puede ejecutar un programa en GDB de varias maneras. O escriba gdb , y una vez que se carga, escribe correr. O inicie gdb y luego use el archivo comando, cargue el binario en gdb y luego ejecútelo con el correr dominio.
Si su programa requiere argumentos de línea de comandos para funcionar correctamente, asegúrese de agregar los argumentos después del nombre del programa. Aquí está la sintaxis para cargar el programa en GDB y ejecutarlo con argumentos:
gdb
run
O:
gdb
file
run
Establecer puntos de interrupción con GDB
Los puntos de interrupción en la depuración son paradas bruscas establecidas manualmente en el código que detienen el flujo de ejecución cuando el programa alcanza un punto de interrupción. Establecer puntos de interrupción le permite recorrer el código e inspeccionar cómo cada etapa de ejecución afecta los datos y las variables.
En GDB, cuando depura un programa con símbolos de depuración, puede establecer un punto de interrupción por el nombre de la función o establecer un punto de interrupción según el número de línea. Aquí está la sintaxis:
break main
break 47
Para ver todos los puntos de interrupción en la sesión de depuración actual, escriba:
info breakpoints
Para eliminar uno o varios puntos de interrupción en particular, escriba:
delete 2
delete 3-5
GDB también le permite establecer puntos de interrupción condicionales, lo que significa que el programa solo se detendrá si se cumple una condición particular durante la ejecución. Podría ser el cambio en el valor de una variable o una llamada de función fallida o cualquier cosa que desee. Aquí está la sintaxis para establecer puntos de interrupción condicionales:
break if n == 2
Si desea continuar la ejecución del programa después de alcanzar un punto de interrupción, escriba el continuar dominio:
continue
Paso a paso por el código
Revisar el código es crucial para comprender cómo el programa maneja los datos. Al recorrer varias funciones de su programa y examinar el estado de los datos, puede obtener una mejor comprensión de cómo el programa implementa la lógica que ha escrito en el código.
También le ayuda a detectar la raíz de los fallos y a estudiar el comportamiento del programa con precisión quirúrgica, ya que puede recorrer cada línea de código como desee. Puede recorrer el código de tres formas principales en GDB:
- paso: Este comando le dice a GDB que pase a la siguiente línea del archivo fuente. Esto le permite esencialmente recorrer la longitud del código fuente línea por línea.
- próximo: Este comando ejecuta la siguiente línea de código fuente dentro de la función actual y luego se detiene. próximo trata una función como una sola línea, por lo que si usa next antes de una llamada a la función, la tratará como una sola línea y la pasará por encima, a diferencia de paso dominio.
- finalizar: El comando finalizar ejecuta todas las líneas restantes dentro de la función actual y luego se detiene.
Examinar variables
A medida que avanza en el código, querrá examinar el valor de las variables para ver cómo la lógica del programa las cambia. Aquí está la sintaxis para ver el valor de las variables en GDB:
print
En caso de que desees imprimir los cambios en el valor de una variable cada vez que se actualiza, debes usar el comando display. Esto es especialmente útil cuando desea rastrear e imprimir el valor de una variable en un bucle:
display
Establecer puntos de vigilancia
Los puntos de observación y los puntos de interrupción condicionales están estrechamente relacionados ya que ambos responden a cambios en un programa. Los puntos de vigilancia se utilizan para rastrear cambios en los datos del código. Por ejemplo, es posible que desee que el programa se interrumpa cada vez que cambie el valor de una variable. Aquí se explica cómo hacerlo con GDB:
watch
Depuración de subprocesos específicos con GDB
GDB le permite realizar depuración específica de subprocesos cuando trabaja con programas multiproceso. Para demostración, trabajaremos con un programa C simple que utiliza cuatro subprocesos para imprimir mensajes con cada subproceso.
Para ver los hilos generados actualmente en su programa, use el información dominio:
info threads
Para trabajar con un hilo específico, puede seleccionarlo de la lista usando su número de índice. Por ejemplo:
thread 2
Después de seleccionar el hilo, puede recorrer su flujo de ejecución utilizando el paso, próximo, y finalizar comandos como se demostró anteriormente.
Depuración remota con GDB
También puede depurar de forma remota programas ubicados en un sistema diferente. Para hacerlo, necesita configurar gdbserver en la máquina de destino. Puede instalarlo fácilmente utilizando el administrador de paquetes predeterminado de su distribución o otros administradores de paquetes que hayas instalado en su sistema.
Por ejemplo, para instalar gdbserver en sus sistemas basados en Ubuntu o Debian, use APT:
sudo apt install gdbserver
Una vez instalado, vaya a la carpeta del binario y ejecute este comando para iniciar gdbserver:
gdbserver :
gdbserver debería devolver el resultado de que está activo y escuchando en el puerto que definiste. Ahora en la máquina cliente, inicie GDB y luego conéctese al servidor remoto usando el objetivo dominio:
target remote :
Escribir scripts GDB para automatizar la depuración
GDB permite a los programadores escribir scripts GDB que ejecutarán comandos GDB automáticamente. Esto es de gran ayuda cuando intentas depurar la misma parte de un código varias veces. En lugar de tener que establecer el punto de interrupción, recorrer el código e imprimir valores de variables cada vez que carga el binario, puede usar un script GDB para automatizar todo el proceso.
He aquí un ejemplo:
set logging enabled on
set logging file sample.out
break main
command 1
backtrace
print N
continue
end
quit
En el script anterior, le está indicando a GDB que habilite el registro y guarde el registro en un archivo llamado muestra.out, luego establezca un punto de interrupción en el principal función.
Para el punto de interrupción número 1, en este caso, el punto de interrupción en la función principal, ejecute los siguientes comandos: rastrear, imprimir, continuar. Básicamente, GDB primero ejecutará un seguimiento, luego imprimirá el valor de la variable "N", continuará la ejecución y finalmente saldrá.
Para ejecutar este script, use:
gdb -x