GDB

Para empezar a ejecutar gdb en emacs se debe teclear:

     [esc] X gdb

En la parte inferior de la pantalla aparecerá un prompt como el siguiente:

     Run gdb (like this):

en el cual se podrá empezar a ejecutar el debugger. Para poder empezar la revisión de algún programa se deberá teclear lo siguiente:

     gdb archivo_ejecutable

Al teclear lo anterior, entraremos al prompt de gdb, el cual esperará que se teclee algún comando propio de gdb para poder empezar. Si corremos gdb con el comando siguiente:

     (gdb) run

sólamente correrá el programa hasta que éste termine, sin importar si fue correcta o incorrectamente. Cuando el programa termina, gdb imprime el mensaje:

     Program exited with code
     (gdb)

en donde n es el código de salida del programa (mayor a cero si el programa termino de manera correcta).

Para terminar el programa cuando está corriendo dentro de gdb, se puede teclear CTRL-C. Esto regresará el control a gdb, el cual esperará a que se teclee un nuevo comando. Para salir completamente de gdb, se necesita teclear el comando "quit":

     (gdb) quit

Si el programa que se está verificando termina de manera anormal, podemos utilizar alguno de los comandos de gdb para averiguar qué fue lo que pasó. El comando "backtrace" nos da un balance mostrándonos qué era exactamente lo que estaba haciendo el programa cuando éste salió. "backtrace" produce una lista de todos los procedimientos activos y los argumentos con los que fueron llamados, empezando del más reciente al último que se llamó.

gdb nos provee de una manera en la que podemos ver el programa que estamos revisando o corrigiendo. Con el comando "list" gdb nos despliega el código fuente del programa en cuestión, numerando cada una de las líneas. Por default, gdb despliega de 10 en 10 líneas el programa con el comando "list". Nosotros podemos especificar de qué línea a qué línea queremos que se despliegue el programa. El comando:

     (gdb) list 10,15

nos despliega de la línea 10 a la 15 de nuestro código en pantalla

Otro comando importante es "whatis", el cual nos permite ver de qué tipo es cierta variable. Supongamos que tenemos en un programa la siguiente declaración:

     int p = 0;

Con el comando:

     (gdb) whatis p

obtendríamos el siguiente resultado:

   type = int

el comando "ptype" es más poderoso que el comando "whatis", ya que, por ejemplo, al llamar al comando "whatis" con una variable de una estructura, únicamente nos desplegaría el tipo de la estructura, a diferencia del comando "ptype", el cual nos desplegaría además, los elementos que componen la estructura.

Además podemos ver qué valor tiene cierta variable, el comando:

     (gdb) print p

nos desplegaría lo siguiente:

     $1 = 0

La función "print" también nos sirve para desplegar el valor que nos regresa una función durante la ejecución de una sesión de debug. Supongamos que en nuestro programa tenemos la siguiente declaración:

     factorial(long numero);

Si nosotros ejecutamos el comando "print" para averiguar qué valor nos regresa la función "factorial", tendríamos que hacer lo siguiente:

     (gdb) print factorial(3)

y obtendríamos el siguiente resultado:

     $2 = 6

Los Breakpoint nos ayudan a detener temporalmente la ejecución del programa para situarnos en algún punto específico de él para de esta manera analizar en dicho punto el valor de cierta variable o función para la detección de errores. El comando "break" sirve para tal efecto y se puede ejecutar de alguna de las siguientes maneras:

break numero_de_linea

break nombre_de_funcion

break linea_o_funcion if condicion

break nombre_de_rutina

Si el tenemos un programa que se compone de varios archivos, podemos ejecutar el comando "break" de la siguiente manera:

break nombre_de_archivo:linea

break nombre_de_archivo:nombre_de_funcion

Una variación de un breakpoint es un watchpoint, el cual sólamente detiene temporalmente le ejecución de un programa en el caso de que se cumpla una condición; por ejemplo, el comando siguiente únicamente detendrá la ejecución del programa si la variable "testsize" alcanza un valor mayor a 100000:

     (gdb)watch testsize > 100000

Como dijimos anteriormente, un breakpoint detiene temporalmente la ejecución de un programa para analizar la situación en determinado punto. Para continuar con la ejecución del programa, se tecleará el comando "continue"

    (gdb) continue

o

     (gdb) c

Para obtener un listado de todos los breakpoint que tenemos en un programa, se puede teclear el comando:

     (gdb) info breakpoints

el cual desplegará una lista enumerada de todos los breakpoints que han sido creados en el programa.

Para borrar los breakpoints, podemos teclear el comando "delete", de tal manera que:

     (gdb) delete

borrará todos los breakpoints del programa. De la misma manera:

     (gdb) delete numero

borrará el numero de breakpoint según la lista desplegada al teclear "info breakpoints".

El comando "clear" tiene el mismo efecto que el comando "delete", de tal manera que al llamar al comando "clear" con un número como argumento, borrará todos los breakpoints que se encuentren en esa línea, al pasarle una función como argumento, borrará todos los breakpoints que se encuentren en dicha función y al ejecutarla sin argumentos borrará todos los breakpoints del programa.

También podemos activar o desactivar breakpoints sin necesidad de borrarlos, para ello tenemos los comandos:

enable numero

disable numero

los cuales activan y desactivan el número de breakpoint especificado, respectivamente.

Con el comando:

     (gdb) set variable variable = valor

podemos asignarle a una variable cierto valor durante la sesión de debug.

Ahora bien, øde qué serviría una sesión de debug si no podemos ejecutar paso a paso el programa para ver en detalle cómo va cambiando el programa línea por línea? Para eso existen los comandos "step" y "next". El primero, en el caso de que se encuentre la llamada a alguna función en una línea, entra a la función y la ejecuta también línea por línea, mientras que el segundo no entra a ejecutar la funcion, sino que la ejecuta en un solo paso, y continúa con la siguiente línea.

El comando "call" llama a ejecutar directamente una función:

     (gdb) call funcion (argumentos)

El comando "finish" termina de ejecutar la función actual e imprime su valor de retorno (en caso de que exista alguno).

El comando "return" cancela la ejecución de la función actual, regresando el valor especificado como argumento.