GNU DEBUGGER (GDB)

Anuncio
GNU DEBUGGER (GDB)
CI-4835: Redes de Computadores
Ene-Mar 2013
Depuración
●
Limpiar, purificar
●
Proceso de identificar y corregir errores
●
El propósito de GDB es permitir que se vea lo que
ocurre “dentro” de otro programa mientras este se
ejecuta, o lo que estaba ocurriendo con otro programa,
cuando este último falló
●
Orden “~$ man gdb”
●
http://sourceware.org/gdb/current/onlinedocs/gdb toc.html
(manual
en línea)
●
●
Para usarlo hay que compilar los programas con la
opción “-g” (~$ gcc -g <nombre_prog.c>)
Otra información en:
http://ldc.usb.ve/~figueira/Cursos/ci3825/taller/material/gdb.html
Ejemplo #1
/* uno.c v1.0 - cuenta la cantidad de "3" y "7" en una serie numérica que lee de un archivo */
#include <stdio.h>
#include <stdlib.h>
char line[100];
int data[5];
void get_data (int *data);
int main ()
{
int seven_count;
int three_count;
int index;
seven_count=0;
three_count=0;
get_data (data);
for (index=0; index<5; ++index)
{
if (data[index] == 3)
++three_count;
if (data[index] == 7)
++seven_count;
}
}
fprintf (stdout, "\nLa secuencia contiene %d sietes y %d tres.\n", seven_count, three_count);
exit (0);
void get_data (int *data)
{
fprintf (stdout, "\nIntroduzca cinco numeros enteros: ");
fgets (line, sizeof(line), stdin);
sscanf (line, "%d %d %d %d %d", &data[1], &data[2], &data[3], &data[4], &data[5]);
}
Anomalía en el Ejemplo 1
●
El
código
no
cuenta
apropiadamente la cantidad de
números “3” que contiene la
secuencia
Shell GDB
●
●
●
Posee un Shell interactivo con funciones de historial
(teclas de flechas) y completar la orden, usando la
tecla “TAB”
Para ayuda desde el shell se puede usar “help”
(gdb) help [<comando>])
La orden “list” (alias “l”) muestra el contenido del
programa que se ejecuta.
(gdb) list [archivo:]funcion
(gdb) list [archivo:]linea[,linea]
(gdb) list
(gdb) list -
Puntos de Interrupción
Un “Breakpoint” es un punto en el cual se interrumpirá la
ejecución del programa y se devolverá el control al “shell”
para poder examinar variables u otras operaciones
● La orden “break” (alias “b”) se usa de las siguientes formas:
(gdb) break [archivo:]función
(gdb) break [archivo:]linea
● La orden “tbreak” se usa para colocar un punto de
interrupción antes de la posición indicada
(gdb) tbreak [archivo:]linea
(gdb) tbreak [archivo:]función
● Un “Watchpoint” es una orden que actúa sobre variables y
detiene la ejecución cuando algún contenido cambia
(gdb) watch nombre_de_la_variable
●
Puntos de Interrupción (cont...)
●
Un “Catchpoint” es un punto de interrupción que
aplica sobre señales
(gdb) catch
●
La orden “info” permite visualizar los puntos
existentes
(gdb) info breakpoints|watchpoints|catch
●
●
Se pueden usar las órdenes “delete”, “disable”,
“enable” e “ignore” sobre los puntos de
interrupción
Un punto de interrupción se puede condicionar
Corriendo el Programa
●
La orden “run” pone a correr el programa
(gdb) run [argumentos]
●
●
Si se desea ejecutar el código desde el principio
se puede usar “bt”, lo cual es una traza hacia
atrás (backtrace)
Si el programa termina por alguna falla particular,
entonces se obtendrá en pantalla algo como:
Corriendo el Programa (cont...)
Después de que el programa se ha detenido en algún punto de interrupción,
para continuar su ejecución se debe usar la orden “continue” (alias “c”)
● La orden “print” (alias “p”) se usa para visualizar el contenido en memoria de
alguna variable y puede emplear un formato específico
(gdb) print [/fmt] expresión
donde /fmt puede estar compuesto por una letra que cambie el formato original
de la variable
● La letra de formato puede ser:
o octal
x hexadecimal
d decimal
u unsigned decimal
f float
a address
t binary
s string
c char
●
Corriendo el Programa
●
La orden “step” restaura la ejecución del programa un
paso a la vez. Es decir, ejecuta una única orden
(gdb) step
●
La orden “next” restaura la ejecución del programa un
paso a la vez, pero si dicha orden es la invocación de
una llamada a una función, ejecuta a la misma como si
fuese una sola orden
(gdb) next
●
La orden “jump” restaura la ejecución del programa a
partir de la línea que se le indica. Es decir, la corrida
salta a la línea señalada
(gdb) jump nro_linea
Resultado del Ejemplo 1
●
●
Después de aplicar los comandos que se muestran
en las imágenes, se observa que data[0] contiene
0 y la secuencia es capturada a partir de data[1].
De modo que se cae en cuenta de que se cometió
un error al trabajar el índice del arreglo data a
partir de “1” y no “0” en la instrucción “sscanf”
Es decir, se direccionó un espacio por afuera del
arreglo. Por lo tanto la cuenta de los contadores no
podía haber sido correcta
Algunas órdenes más
●
La orden “set” sirve para alterar la ejecución de una variable en medio de la
corrida
x set variable=expresión
●
La orden “display” se emplea para permitir que cada vez que el programa se
detenga muestre lo que se le indica
display [/fmt] expresión
donde /fmt puede estar compuesto por un número -contador-, una letra de
formato y una letra de tamaño.
●
La letra del tamaño puede ser:
b byte
h halfword
w word
g giant (8 bytes)
●
Así por ejemplo “(gdb) display /10xb arreglo” indica que se debe mostrar, en
notación hexadecimal, el contenido de los siguientes 10 bytes a partir de
arreglo
Ejemplo #2
/* Segundo ejemplo */
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
int main () {
int i, j;
long ahora;
/* Tomando la semilla desde el reloj del computador. */
srand (time(&ahora) % 37);
printf ("\nGenerando un valor pseudoaleatorio:");
/* Se usa el generador de números pseudoaleatorios "rand". Este
generador es del tipo congruencial multiplicativo, con un período de 2
elevado a la 32 (4294967296). Es decir, al término de esos intentos
vuelve a repetir valores. Los números que produce oscilan entre 0 y 2
elevado a la 15 menos una unidad */
}
i=rand ();
j=rand();
j-=j;
i=i/j;
fprintf (stdout, "\ni=%d y j=%d\n", i, j);
exit (0);
Anomalía en el Ejemplo 2
●
El código no termina de ejecutarse,
ya que se presenta una excepción,
se aborta la corrida y se genera un
archivo de vaciado de la memoria
Lectura del archivo Core
●
La orden para leer el “core” es:
~$ gdb -c <archivo_core> <archivo_ejecutable>
Resultado del Ejemplo 2
●
●
Al leer el archivo “core” GDB indica que el
programa terminó con una señal tipo “8”. Al
ejecutar la orden “~$ man 7 signal” se puede
constatar que se trata de SIGFPE, una
anomalía del tipo expresión aritmética real
El depurador muestra además que la operación
es una división. Cuando se examinan los
valores de las variables, se observa que el
problema es que se está dividiendo por cero
Algunas órdenes más
●
La pila de ejecución del proceso puede examinarse con el
comando “backtrace”, alias “bt”
(gdb) backtrace
#0 func2 (x=30) at test.c:5
#1 0x80483e6 in func1 (a=30) at test.c:10
#2 0x8048414 in main (argc=1, argv=0xbffffaf4) at test.c:19
#3 0x40037f5c in __libc_start_main () from /lib/libc.so.6
(gdb)
El ejemplo muestra que func2() fue invocada por func1(), que a su
vez fue invocada por main(). Cada frame tiene un número a la
izquierda que lo identifica
●
Existen órdenes para examinar y manipular el “stack”, incluso con
aquellas variables que se encuentran en otros contextos de
ejecución que no son el local. La orden “frame” permite cambiar a
algún marco de ejecución almacenado en la pila
frame [N]
Algunas órdenes más (cont...)
●
(gdb) backtrace
#0 func2 (x=30) at test.c:5
#1 0x80483e6 in func1 (a=30) at test.c:10
#2 0x8048414 in main (argc=1, argv=0xbffffaf4) at test.c:19
#3 0x40037f5c in __libc_start_main () from /lib/libc.so.6
(gdb) frame 2
#2 0x8048414 in main (argc=1, argv=0xbffffaf4) at test.c:19
19
x = func1(x);
(gdb)
El ejemplo muestra como, a pesar de haber ocurrido un punto de
interrupción en func2(), se pasa a operar en el “marco” apilado
para main()
●
La orden “info frame” se usa para mostrar la información
vinculada con el “marco corriente”
Algunas órdenes más (cont...)
●
●
La orden “info locals” se usa para mostrar la información de las variables
guardadas en el marco
La orden “info args” se emplea para visualizar los argumentos registrados en
el marco
(gdb) info frame
Stack level 2, frame at 0xbffffa8c:
eip = 0x8048414 in main (test.c:19); saved eip 0x40037f5c
called by frame at 0xbffffac8, caller of frame at 0xbffffa5c
source language c.
Arglist at 0xbffffa8c, args: argc=1, argv=0xbffffaf4
Locals at 0xbffffa8c, Previous frame's sp is 0x0
Saved registers:
ebp at 0xbffffa8c, eip at 0xbffffa90
(gdb) info locals
x = 30
s = 0x8048484 "Hello World!\n"
(gdb) info args
argc = 1
argv = (char **) 0xbffffaf4
Algunas órdenes más (cont...)
●
●
El ejemplo anterior muestra el contenido de
los registros Instruction Pointer (EIP) y
Base Pointer (EBP) de un procesador del
tipo Intel familia 8088. Conociendo el código
que se procesa, comprendiendo los
principios básicos de manejo de bajo nivel
de un procesador -ensamblador- y con
práctica suficiente, se puede identificar y
corregir los errores
Hay más alternativas de órdenes en GDB,
pero esta presentación es únicamente una
introducción
Mayor información en:
http://www.dirac.org/linux/gdb/
http://gnu.org/software/gdb/docume
ntation/
Descargar