Depuración con gdb

El depurador GNU (gdb) le permite examinar el funcionamiento interno de otro programa mientras se ejecuta el programa o retrospectivamente ver qué estaba haciendo un programa en el momento en que se produjo el bloqueo.

El gdb le permite examinar y controlar la ejecución de código y es útil para evaluar las causas de los bloqueos o del comportamiento incorrecto general. gdb no maneja procesos Java™ , por lo que es de uso limitado en un programa Java puro. Es útil para depurar bibliotecas nativas y la propia JVM.

Ejecución de gdb

Puede ejecutar gdb de tres maneras:

Inicio de un programa
Normalmente, el mandato: gdb <application> se utiliza para iniciar un programa bajo el control de gdb. Sin embargo, debido a la forma en que se inicia Java, debe iniciar gdb estableciendo una variable de entorno y, a continuación, llamando a Java:
export IBM_JVM_DEBUG_PROG=gdb
java
A continuación, recibirá una solicitud gdb y proporcionará el mandato de ejecución y los argumentos Java:
r <java_arguments>
Conexión a un programa en ejecución
Si un programa Java ya está en ejecución, puede controlarlo en gdb. El ID de proceso del programa en ejecución es necesario y, a continuación, gdb se inicia con la aplicación Java como primer argumento y el ID de proceso como segundo argumento:
gdb <Java Executable> <PID>

Cuando gdb se conecta a un programa en ejecución, este programa se detiene y su posición en el código se muestra para el visor. Entonces, el programa está bajo el control de gdb y podrá empezar a emitir mandatos para establecer y visualizar las variables y controlar generalmente la ejecución del código.

Ejecución en un volcado del sistema (archivo clase Core)
Un volcado del sistema normalmente se produce cuando se bloquea un programa. gdb puede ejecutarse en este volcado del sistema. El volcado del sistema contiene el estado del programa cuando se produjo el bloqueo. Utilice gdb para examinar los valores de todas las variables y registros que llevan hasta un bloqueo. Esta información le ayuda a descubrir la causa del bloqueo. Para depurar un vuelco del sistema, inicie gdb con el archivo de aplicación Java como primer argumento y el nombre de vuelco del sistema como segundo argumento:
gdb <Java Executable> <system dump>

Cuando se ejecuta gdb en un volcado del sistema, inicialmente muestra información como, por ejemplo, la señal de terminación que ha recibido el programa, la función que se estaba ejecutando en ese momento, e incluso la línea de código que ha generado el error.

Cuando un programa está bajo el control de gdb, se muestra un mensaje de bienvenida seguido de una solicitud (gdb). El programa está ahora a la espera de que usted introduzca las instrucciones. Para cada instrucción, el programa continúa en el camino que elija.

Establecimiento de puntos de interrupción y puntos de observación

Los puntos de interrupción pueden establecerse para una determinada línea o función utilizando el mandato:

break linenumber

or

break functionName

Después de haber establecido un punto de interrupción, utilice el mandato continue para permitir que el programa se ejecute hasta que alcance un punto de interrupción.

Establezca puntos de interrupción utilizando condicionales de modo que el programa sólo se detenga cuando se alcance la condición especificada. Por ejemplo, la utilización de breakpoint 39 if var == value hace que el programa se detenga cuando llegue a la línea 39, pero sólo si la variable es igual al valor especificado.

Si desea saber dónde así como cuándo una variable se ha convertido en un determinado valor, puede utilizar un punto de observación. Establezca el punto de observación cuando la variable en cuestión esté dentro del ámbito. Después de hacerlo, recibirá una alerta cada vez que la variable llegue al valor especificado. La sintaxis del mandato es: watch var == value.

Para ver qué puntos de interrupción y puntos de observación están establecidos, utilice el mandato info:

info break
info watch
Cuando gdb alcance un punto de interrupción o un punto de observación, imprime la línea de código que está establecida a continuación para ejecutarse. Establecer un punto de interrupción en la línea 8 hará que el programa se detenga después de completar la ejecución de la línea 7, pero antes de la ejecución de la línea 8. Además de puntos de interrupción y puntos de observación, el programa también se detiene cuando recibe ciertas señales del sistema. Si utiliza los siguientes mandatos, puede detener la herramienta de depuración que se para cada vez que recibe estas señales del sistema:
handle sig32 pass nostop noprint 
handle sigusr2 pass nostop noprint 

Examinar el código

Cuando se ha alcanzado la posición correcta del código, existen diversas maneras de examinar el código. La más útil es backtrace (abreviado a bt), que muestra la pila de llamadas. La pila de llamadas es la colección de marcos de función, donde cada marco de función contiene información como, por ejemplo, parámetros de función y variables locales. Estos marcos de función se colocan en la pila de llamadas en el orden en que se ejecutan. Esto significa que la función llamada más recientemente se visualiza en la parte superior de la pila de llamadas. Puede seguir la ruta de ejecución de un programa examinando la pila de llamadas. Cuando se visualiza la pila de llamadas, muestra un número de marco en el inicio de la línea, seguido de la dirección de la función de llamada, seguido del nombre de función y del archivo de origen de la función. Por ejemplo:
#6 0x804c4d8 in myFunction () at myApplication.c

Para ver información más detallada sobre un marco de función, utilice el mandato frame junto con un parámetro que especifique el número de marco. Después de seleccionar un marco, puede visualizar sus variables utilizando el mandato print var.

Utilice el mandato print para cambiar el valor de una variable; por ejemplo, print var = newValue.

El mandato info locals muestra los valores de todas las variables locales en la función seleccionada.

Para seguir la secuencia exacta de ejecución del programa, utilice los mandatos step y next. Ambos mandatos aceptan un parámetro opcional que especifica el número de líneas para ejecutar. Sin embargo, next trata las llamadas de función como una sola línea de ejecución, mientras que step avanza por cada línea de la función a la que se ha llamado, un paso cada vez.

Mandatos útiles

Cuando ha terminado de depurar el código, el mandato run hace que el programa se ejecute hasta su final o su punto de bloqueo. El mandato quit se utiliza para salir de gdb.

Otros mandatos útiles son:

ptype
Imprime el tipo de datos de la variable.
info share
Imprime los nombres de las bibliotecas compartidas que están actualmente cargadas.
info functions
Imprime todos los prototipos de función.
list
Muestra las 10 líneas de código fuente que están junto a la línea actual.
help
Muestra una lista de temas, cada uno de los cuales puede tener el mandato help asociado al mismo, para visualizar ayuda detallada sobre cada tema.