Uso b谩sico de GDB

GDB es una utilidad que permite depurar programas en varios lenguajes de programaci贸n. En el curso la usaremos para depurar programas en C.

Ejecutar un programa en GDB

Para ejecutar el c贸digo compilado en GDB, se usa el comando env - gdb <nombre_programa>, donde <nombre_programa> es el nombre del programa a depurar.

(驴Por qu茅 partimos el comando con env -? Porque las variables de entorno afectar谩n la ubicaci贸n de nuestra pila. Pueden ver esta pregunta de Stack Overflow para m谩s informaci贸n.)

Al partir GDB, el programa no se ejecuta todav铆a, pero GDB muestra una consola interactiva. Para conocer los comandos utilizables, es posible ejecutar help.

Usar argumentos

Para ejecutar el c贸digo compilado en GDB y usar argumentos en el ejecutable, se usa el comando gdb --args <nombre_programa> <args...>, donde <nombre_programa> es el nombre del programa a depurar y <args> es uno o m谩s argumentos que recibir谩 el programa a depurar.

Explorar c贸digo asm

Para explorar una funci贸n en asm, se puede ejecutar el comando disassemble <nombre_func> o disass <nombre_func>, donde <nombre_func> es el nombre de la funci贸n que se quiere revisar. Tambi茅n se puede usar una direcci贸n de memoria en vez de un nombre de funci贸n. Si no colocan nada luego de disassemble o disass, se mostrar谩 el c贸digo asm cercano a la l铆nea que se est谩 ejecutando en ese momento.

Colocar Breakpoints

Antes de la ejecuci贸n del programa, es necesario colocar breakpoints o zonas en las cuales el c贸digo dejar谩 de ejecutarse, a la espera del control de nosotros.

Los breakpoints se colocan con el comando break <f>, donde <f> corresponde a la funci贸n en la cual se detendr谩 la ejecuci贸n del programa, una direcci贸n de memoria o el n煤mero de la l铆nea en el c贸digo fuente.

Una idea para partir debuggeando en GDB es colocar un break en la funci贸n main. De esta forma podemos controlar el flujo del programa desde su inicio. Esto se hace escribiendo break main.

Flujo del programa

Para partir el programa en GDB, puedes escribir r. El programa se detendr谩 tanto si espera input interactivo (funci贸n gets()) como si se coloc贸 un breakpoint en alguna funci贸n que se est茅 ejecutando.

En el caso de detenci贸n por un breakpoint, se pueden usar las siguientes opciones:

  • frame <i> o f <i>: les muestra la instrucci贸n en la que se encuentran i frames m谩s arriba del que se encuentran (conteo parte en 0). Pueden omitir el par谩metro <i> para que GDB les muestre la l铆nea de c贸digo del frame actual.
  • continue <i> o c <i>: la cual contin煤a el flujo normal del programa, salt谩ndose i breakpoints. Si omiten <i>, se contin煤a solamente hasta el breakpoint siguiente.
  • step <i> o s <i>: la cual avanza i instrucciones en el programa. Si esta instrucci贸n es una funci贸n, contin煤a revisando dentro del frame de la funci贸n. Es posible omitir el par谩metro <i> para avanzar solamente una instrucci贸n.
  • stepi <count> o si <count>: les permite avanzar a i instrucciones en asm. Para ver en qu茅 instrucci贸n de asm van, pueden escribir disass (Una flecha en el lado izquierdo de la pantalla indica la instrucci贸n actual). Al igual que con step, en caso de no colocar un n煤mero,
  • next o n: la cual pasa a la siguiente instrucci贸n en el programa dentro del frame actual, es decir, si la instrucci贸n es una funci贸n, la ejecuta sin pausar y se detiene justo despu茅s que 茅sta retorna.
  • finish o fin: La cual termina el frame actual y se detiene apenas se vuelve al frame anterior.

Mientras se van ejecutando estos pasos, GDB muestra la l铆nea de c贸digo en la que va el programa, lo que ayuda a ubicarse en su flujo.

Informaci贸n general

Existen comandos que muestran informaci贸n general del estado actual del programa:

  • info args muestra los argumentos recibidos por la funci贸n actual.
  • info all-registers muestra el valor actual de todos los registros del procesador.
  • info frame muestra informaci贸n sobre el frame actual.
  • info locals muestra las variables locales definidas hasta este momento.
  • x/<n><type><size> <addr>, donde <addr> corresponde a una direcci贸n de memoria o el nombre de un registro ($rsp por ejemplo para el tope de la pila), n representa a la cantidad de valores a leer desde ese punto, type corresponde al tipo de dato a interpretar y size corresponde al tama帽o del dato; permite mostrar los n valores de tipo type en tama帽o size desde la direcci贸n addr. Algunas opciones de tama帽o 煤tiles son:
    • g: 1 palabra grande (64 bits)
    • w: 1 palabra (32 bits)
    • h: 1 media palabra (16 bits)
    • b: 1 byte (8 bits) Mientras que algunas opciones de tipo 煤tiles son:
    • o: como un n煤mero octal
    • x: hexadecimal
    • d: decimal con signo
    • u: decimal sin signo
    • t: binario
    • f: coma flotante
    • a: direcci贸n de memoria
    • c: caracter
    • s: Cadena de texto
    • i: Instrucci贸n (como si fuera ASM)
  • p/<type> <var>, donde <var> corresponde a una variable y type a un tipo al igual que en el comando anterior, permite examinar el valor de ese espacio.
  • help <cmd> les muestra ayuda sobre alg煤n comando. Ejemplo: help c.

Ejemplos de uso:

驴C贸mo determinar el estado de la pila ?

  • Correr el programa con GDB
  • Colocar un breakpoint cerca de la variable que se quiere analizar (por ejemplo, en el nombre de la funci贸n): b func_name.
  • Correr el programa con r. Se detendr谩 al inicio de la funci贸n.
  • Avanzar con n hasta pasar la definici贸n/asignaci贸n de la variable
  • escribir x/5xg $rsp mostrar谩 el valor de las 5 primeras palabras grandes de la pila. Al mismo tiempo, se muestra la direcci贸n de memoria de cada valor en color azul al inicio de cada fila.
  • Presionar c para que el programa contin煤e hasta su final.

Editar en GitHub Modificado por 煤ltima vez el 07/02/2022 a las 23:44:42 hrs.