fbpx Comando gdb en Linux: Depurar Programas Compilados con GCC | Certificação Linux

Comando gdb en Linux: Depurar e Inspeccionar Programas Compilados con GCC

📅 07/12/2021 ⏱ 10 min ✍️ Uira Ribeiro
Linuxcomandos
Comando gdb en Linux: Depurar e Inspeccionar Programas Compilados con GCC
Exam Pass App — mais de 7.000 questões LPI, offline, em 5 idiomas, disponível no Android e na App Store
Disponible en
Google Play
Disponible en
App Store

El Comando gdb en Linux es una herramienta muy útil para depurar software compilado con el GCC.

Utilizando el depurador gdb por primera vez

Para que el depurador pueda funcionar, es necesario que el software sea compilado con la opción "-g" de gcc, de manera que el compilador proveerá información de depuración en el código objeto.

Ejemplo:

$ gcc –wall –g principal.c rede.c interface.c –o pingnovo

La idea principal para depurar un programa es insertar un breakpoint en el punto donde deseas iniciar la depuración en una determinada línea N del código.

El breakpoint hace una pausa en la ejecución del programa en algún punto determinado que se desee examinar con más cuidado.

Después de insertar el breakpoint, se debe ejecutar el programa dentro del gdb y avanzar en la ejecución, verificando los parámetros pasados a las funciones, el tipo y contenido de las variables, hasta que se encuentre el error. Entonces, se corrige el error en el código fuente y se compila nuevamente el programa.

Para utilizar el gdb es simple:

# gdb programa-executávelGNU gdb 5.3.92Copyright 2003 Free Software Foundation, Inc.GDB is free software, covered by the GNU General Public License, and you arewelcome to change it and/or distribute copies of it under certain conditions.Type "show copying" to see the conditions.There is absolutely no warranty for GDB.  Type "show warranty" for details.This GDB was configured as "i586-suse-linux"...(gdb)

Su interfaz es basada en comandos de Linux con sintaxis relativamente simples.

Los comandos pueden ser escritos de forma completa o simplificada, generalmente usando solo sus primeras letras. Los parámetros como números de línea y nombres de variables se pasan inmediatamente después del nombre del comando.

Veamos los comandos más importantes:

Para insertar un breakpoint en una determinada línea del código:

break N 
o 
b N

Donde N es la línea de código donde se desea detener la ejecución del programa. Para esto, puede ser necesario visualizar el código fuente del programa.

Para eliminar todos los breakpoints:

delete
o 
d

Para ejecutar el programa hasta encontrar el primer breakpoint:

run
o 
r 

Para listar el código fuente del programa:

list
o 
l

Para ejecutar las siguientes instrucciones del programa. Una instrucción puede entenderse como una función:

next N 
o 
n N

Donde N es el número de instrucciones.

Para ejecutar las siguientes N líneas después del breakpoint:

step N 
o 
s N

Para finalizar el programa:

kill
o 
k

Para mostrar información sobre el tipo de una variable:

what variable 
o 
w variable 

Para mostrar el contenido de una variable:

print variable 
o 
p variable

Para ver el estado de una variable en cada paso de la ejecución:

display variablel 

Para ver el contenido de todas las variables instanciadas:

info locals

Para ver los registros del programa:

info registers

Para ver el código assembly del programa:

disassemble

Para ver la pila de recursión:

backtrace
o 
bt

Para obtener ayuda sobre algún comando:

help comando 
o 
h comando

Para salir del gdb:

quit
o 
q

Ejemplo de depuración de un programa

Depurar programas sin usar herramientas apropiadas puede ser una tarea agotadora y a menudo imposible. Para ayudar en esta tarea, se presenta un ejemplo del procedimiento para descubrir los problemas usando el GDB.

El siguiente programa de ejemplo fue creado para provocar un error de cálculo de punto flotante:

#include <stdio.h>float calculo(int numero1, int numero2){  int diferenca;  float resultado;  diferenca = numero1 - numero2;  resultado = numero1 / diferenca;  return resultado;}int main(int argc, char *argv[]){  int valor, divisor, i;  float resultado, total;  valor = 10.1;  divisor = 6;  total = 0;  for(i = 0; i < 10; i++)  {    resultado = calculo(valor, divisor);        total += resultado;        printf("%d  dividido por %d é %f. A soma dos resultados é %f.\n", valor, valor-divisor, resultado,total);    divisor++;    valor--;  }return 0;}

Para compilar este programa guardado como "erro.c":

$ gcc –g erro.c –o erro

La opción "-g" compila el programa con la información necesaria para la depuración.

Este programa debería ejecutar un bucle diez veces y calcular el valor acumulado de divisiones sucesivas. Sin embargo, al ejecutarlo, un error abortará su ejecución:

$ ./erro10  dividido por 4 é 2.000000. A soma dos resultados é 2.000000.9  dividido por 2 é 4.000000. A soma dos resultados é 6.000000.Floating point exception

Para hacer la depuración es necesario ejecutar el programa a través del GDB:

$ gdb erroGNU gdb 5.3.92Copyright 2003 Free Software Foundation, Inc.GDB is free software, covered by the GNU General Public License, and you arewelcome to change it and/or distribute copies of it under certain conditions.Type "show copying" to see the conditions.There is absolutely no warranty for GDB.  Type "show warranty" for details.This GDB was configured as "i586-suse-linux"...(gdb)

El programa podrá ejecutarse dentro del GDB con el comando "run":

(gdb) runStarting program: /root/sistemas/erro10  dividido por 4 é 2.000000. A soma dos resultados é 2.000000.9  dividido por 2 é 4.000000. A soma dos resultados é 6.000000.Program received signal SIGFPE, Arithmetic exception.0x0804835e in calculo (numero1=8, numero2=8) at gdb.c:77         resultado = numero1 / diferenca;

El GDB indicó que el programa realizó una operación matemática ilegal en la línea 7 precisamente en la función calculo:

Los valores de las variables numero1 y numero2 son 8. Podemos listar el código fuente del programa para ver lo que está haciendo con el comando "list":

(gdb) list2       float calculo(int numero1, int numero2)3       {4         int diferenca;5         float resultado;6         diferenca = numero1 - numero2;7         resultado = numero1 / diferenca;8         return resultado;9       }10      int main(int argc, char *argv[])11      {

El comando list listará el código de 10 en 10 líneas. Podrá repetirse hasta que se muestre todo el código.

Como primer paso es interesante examinar el contenido de las variables con el comando "print":

(gdb) print numero1$1 = 8(gdb) print numero2$2 = 8(gdb) print diferenca$3 = 0

En la línea 7 del programa donde ocurrió el error, se puede verificar que la operación "resultado = numero1 / diferencia". Analizando el valor de las variables y la instrucción se puede deducir que el programa está intentando hacer una división por cero.

Podemos continuar el procesamiento del programa con el comando "continue":

(gdb) continueContinuing.Program terminated with signal SIGFPE, Arithmetic exception.The program no longer exists.

Como el error división por cero aborta la ejecución, el programa no continuará. Será necesario usar los breakpoints y ejecutar el programa nuevamente. Es interesante instalar el punto de parada en la función main antes de la llamada de la función calculo.

(gdb) list10      int main(int argc, char *argv[])11      {12        int valor, divisor, i;13        float resultado, total;14        valor = 10.1;15        divisor = 6;16        total = 0;17        for(i = 0; i < 10; i++)18        {19          resultado = calculo(valor, divisor);20              total += resultado;21              printf("%d  dividido por %d é %f. A soma dos resultados é %f.\n", = valor, valor-divisor, resultado,total);22          divisor++;23          valor--;24        }25      return 0;

Podemos instalar el punto de parada en la línea 12 al inicio de la función main y ejecutar nuevamente el programa:

(gdb) break 12Breakpoint 1 at 0x8048384: file gdb.c, line 12.(gdb) runStarting program: /root/sistemas/erroBreakpoint 1, main (argc=1, argv=0xbfffd874) at gdb.c:1414        valor = 10.1;

El procesamiento se detendrá en la línea 14 que es la que contiene la instrucción significativa después de la línea 12. Podemos avanzar el procesamiento línea a línea con el comando "next":

(gdb) next15        divisor = 6;(gdb) next16        total = 0;(gdb) next17        for(i = 0; i < 10; i++)

Los contenidos de las variables podrán ser mostrados con el comando "print" seguido del nombre de la variable:

(gdb) print valor$5 = 10(gdb) print divisor$6 = 6

El valor de todas las variables instanciadas podrá ser visto con el comando "info locals":

(gdb) info localsvalor = 10divisor = 6i = 0resultado = -1.99878407total = 0

El siguiente paso es ejecutar el programa línea a línea hasta que el contenido de las variables valor y divisor sea 8. El comando "display" permite que el contenido de una variable sea mostrado en cada instrucción procesada:

(gdb) display valor1: valor = 10(gdb) display divisor2: divisor = 6

El avance de las instrucciones podrá ser hecho con el comando "next":

(gdb) next20              total += resultado;2: divisor = 61: valor = 10(gdb) next21              printf("%d  dividido por %d é %f. A soma dos resultados é %f.\n", valor, valor-divisor, resultado,total);2: divisor = 61: valor = 10(gdb) next10  dividido por 4 é 2.000000. A soma dos resultados é 2.000000.22          divisor++;2: divisor = 61: valor = 10(gdb) next23          valor--;2: divisor = 71: valor = 10(gdb) next17        for(i = 0; i < 10; i++)2: divisor = 71: valor = 9(gdb) next19          resultado = calculo(valor, divisor);2: divisor = 71: valor = 9(gdb) next20              total += resultado;2: divisor = 71: valor = 9(gdb) next21              printf("%d  dividido por %d é %f. A soma dos resultados é %f.\n", valor, valor-divisor, resultado,total);2: divisor = 71: valor = 9(gdb) next9  dividido por 2 é 4.000000. A soma dos resultados é 6.000000.22          divisor++;2: divisor = 71: valor = 9(gdb) next23          valor--;2: divisor = 81: valor = 9(gdb) next17        for(i = 0; i < 10; i++)2: divisor = 81: valor = 8

En este punto, la función calculo va a retornar la división por cero. El valor de la variable podrá ser cambiado en ejecución para evadir el error con el comando "set":

(gdb) info localsvalor = 8divisor = 8i = 1resultado = 4total = 6(gdb) set valor = 10(gdb) info localsvalor = 10divisor = 8i = 1resultado = 4total = 6

El programa continuará el procesamiento hasta encontrar otra división por cero.

(gdb) next19          resultado = calculo(valor, divisor);2: divisor = 81: valor = 10(gdb) next20              total += resultado;2: divisor = 81: valor = 10(gdb) next21              printf("%d  dividido por %d é %f. A soma dos resultados é %f.\n", valor, valor-divisor, resultado,total);2: divisor = 81: valor = 10(gdb) next10  dividido por 2 é 5.000000. A soma dos resultados é 11.000000.22          divisor++;2: divisor = 81: valor = 10(gdb) next23          valor--;2: divisor = 91: valor = 10(gdb) next17        for(i = 0; i < 10; i++)2: divisor = 91: valor = 9(gdb) next19          resultado = calculo(valor, divisor);2: divisor = 91: valor = 9(gdb) nextProgram received signal SIGFPE, Arithmetic exception.0x0804835e in calculo (numero1=9, numero2=9) at gdb.c:77         resultado = numero1 / diferenca;

En el caso de este ejemplo, el programa está en la declaración de las variables como enteros no permitiendo el resto de una división.

El GDB es un poderoso depurador de programas. Lo animamos a instalar una interfaz gráfica para él para facilitar su uso. Hay otros depuradores también disponibles.

Aprenda mucho más sobre Linux en nuestro curso en línea. Puede effectuer la inscripción aquí. Si ya tiene una cuenta, o quiere crear una, basta con entrar o crear su usuario aquí.

¿Te gustó? Comparte

Uira Ribeiro

Prof. Uirá Ribeiro

Chair do Board do Linux Professional Institute

Después de años viendo profesionales perder horas en tareas simples por no conocer las herramientas correctas de Linux, decidí enseñar.
Hoy soy autor de la mayoría de los Materiales de Aprendizaje oficiales de la LPI y mentor de más de 14,000 alumnos certificados.

Conoce mi historia completa →

Eso fue solo una pieza. El curso enseña el camino completo — desde tu primer comando hasta el día del examen.

Certificação Linux — a plataforma líder em certificações Linux no Brasil
WhatsApp