Publicado el 18 de Diciembre del 2020
566 visualizaciones desde el 18 de Diciembre del 2020
440,2 KB
59 paginas
Creado hace 17a (20/02/2008)
Curso LINUX
AREA 2 : Depuración y optimización
Depuración
● Los errores de programación son inevitables
● La depuración es el proceso de localizar y
eliminar los errores de los programas
● Cuando algo sale mal y no se consigue
averiguar porqué, es mejor apuntar con un
depurador y ver cómo falla
● Se necesita añadir los símbolos de
compilación al ejecutable (opción -g)
Depurador - gdb
● Un depurador permite:
– controlar la ejecución
– cambiar el estado del programa subordinado
● Depuradores en UNIX
– V7 : adb
– System III : sdb
– gdb (1988 ->)
gdb
● The GNU project debugger
● depurador a nivel de código fuente
● portable
● fácil de utilizar
● Depurador de línea de comandos
● Existen múltiples front-ends gráficos
– ddd
– insight
gdb – C / C++
● gdb comprende C y C++
● Permite emplear los mismos nombre que en
el código fuente
● comprende expresiones en C
– *ptr>x.a[1]>q
Ejecución de gdb
● gdb [opciones] [ejecutable [archivocore]]
● ejecutable : archivo a ejecutar
● archivocore : coredump generado por un
programa abortado
Ejemplo core
/* Archivo dia6abort.c */
#include <stdio.h>
#include <stdlib.h>
void recurse (void)
{
static int i;
if (++i==3)
abort();
else
recurse();
}
int main ()
{
recurse();
}
gdb con core
● ulimit c 1024
● gcc g dia6abort.c o dia6abort
● ./dia6abort
● Aborted (core dumped)
● file core
●
core: ELF 32bit LSB core file Intel 80386, version 1 (SYSV), SVR4style
● gdb dia6abort core
gdb – core (2)
GNU gdb 6.4debian
...
Core was generated by `./ch15abort'.
Program terminated with signal 6, Aborted.
warning: Can't read pathname for load map:
Input/output error.
Reading symbols from
/lib/tls/i686/cmov/libc.so.6...done.
Loaded symbols for
/lib/tls/i686/cmov/libc.so.6
Reading symbols from /lib/ld
linux.so.2...done.
Loaded symbols for /lib/ldlinux.so.2
#0 0xffffe410 in __kernel_vsyscall ()
(gdb)
gdb – core (3)
(gdb) where
#0 0xffffe410 in __kernel_vsyscall ()
#1 0xb7dda9a1 in raise () from /lib/tls/i686/cmov/libc.so.6
#2 0xb7ddc2b9 in abort () from /lib/tls/i686/cmov/libc.so.6
#3 0x08048382 in recurse () at ch15abort.c:8
#4 0x08048387 in recurse () at ch15abort.c:10
#5 0x08048387 in recurse () at ch15abort.c:10
#6 0x080483aa in main () at ch15abort.c:15
(gdb)
gdb - where
● El comando where imprime un seguimiento
de la pila
● Lista de todas las funciones llamadas,
empezando por la más reciente
● El comando bt (backtrace) es un alias para
where.
● cada invocación de función en la pila se
llama marco (frame), lo que aparece con #
gdb – frame / list
(gdb) frame 3
#3 0x08048382 in recurse () at ch15abort.c:8
8 abort();
(gdb) list
3
4 void recurse (void)
5 {
6 static int i;
7 if (++i==3)
8 abort();
9 else
10 recurse();
11 }
12
(gdb)
gdb - list
● list muestra las líneas de código de la
función invocada
● Si se pulsa intro se repite la última acción
● El editor de comandos utiliza readline (como
vi o bash), pueden usarse los mismos
comandos.
gdb – puntos de interrupción
● Se puede definir un punto de interrupción
por:
– nombre de función
– número de línea de código
– archivo y numero de línea
– etc.
● El comando run inicia el programa
● break fija el punto de ruptura
gdb - breakpoints
● break expresion : crea un punto de
ruptura
● b file:n : crea un punto de ruptura
coincidiendo con la línea n del alchivo file
● clear expresion : borra los breakpoints
de esa expresion
● delete : borra todos los breakpoints
● delete rango : borra un rango de
breakpoints
Ejemplo
gdb dia6abort
GNU gdb 6.4debian
...
(gdb) b recurse
Breakpoint 1 at 0x8048366: file dia6abort.c, line 7.
(gdb) run
Starting program: /home/espinosa/curso/debug/dia6abort
Breakpoint 1, recurse () at dia6abort.c:7
7 if (++i==3)
(gdb)
Breakpoint condicionales
● Se pueden poner condiciones a los
breakpoints:
– b hello if i==7
● Se pueden cambiar las condiciones de los
breakpoints con condition
– condition 1 i==8
● condition n : elimina la condicion del
breakpoint n
gdb – next / step
● next ejecuta la siguiente instrucción
● step ejecuta la siguiente invocación (entra
en la función)
(gdb) next
10 recurse();
(gdb) next
Breakpoint 1, recurse () at dia6abort.c:7
7 if (++i==3)
(gdb)
gdb – cont / quit
● cont – continua con la ejecución del
programa hasta el siguiente punto de ruptura
o el final del mismo.
● quit – abandona la depuración del programa
(gdb) continue
Continuing.
Breakpoint 1, recurse () at dia6abort.c:7
7 if (++i==3)
(gdb) quit
The program is running. Exit anyway? (y or n)
continue / return
● continue puede recibir como parámetro un
número que indica el numero de breakpoints
a ignorar antes de volver a parar
● return : continua la ejecución fuera de la
función en la que nos encontremos
● jump linea : continua la ejecución en otra
línea de código
gdb - watch
● Un punto de inspección es como uno de
interrupción pero para datos
● watch nombre_de_variable
● La variable se revisa y cada vez que cambia
el valor se para el programa
● En cualquier momento se puede interrumpir
la ejecución con ctrl-c
gdb - watch
(gdb) watch recurse::i
Hardware watchpoint 1: recurse::i
(gdb) run
Starting program: dia6abort
Hardware watchpoint 1: recurse::i
Hardware watchpoint 1: recurse::i
Hardware watchpoint 1: recurse::i
Hardware watchpoint 1: recurse::i
Old value = 0
New value = 1
0x08048373 in recurse () at dia6abort.c:7
7 if (++i==3)
(gdb) c
Continuing.
Hardware watchpoint 1: recurse::i
Old value = 1
New value = 2
0x08048373 in recurse () at dia6abort.c:7
7 if (++i==3)
(gdb) c
Continuing.
Hardware watchpoint 1: recurse::i
Old value = 2
New value = 3
0x08048373 in recurse () at dia6abort.c:7
7 if (++i==3)
gdb - attach
● gdb permite engancharse a un proceso ya
corriendo para ver qué está haciendo
● Si ese programa no dispone de los simbolos
de depuración, simplemente veremos las
llamadas a funciones
● attach pid intenta enlazarse con el
proceso en ejecución con ese pid
ejemplo - attach
● Lanzar el servidor corba del dia 4 en
background
● ps axuw | grep servidor
● ejecutar gdb servidor
● attach pid
● gdb nos permite informarnos sobre los
threads
● info threads
Threads
● Notificación automática de threads
● info threads : información sobre los threads
del programa
● thread n : cambia el contexto de depuración
a ese thread
● thread apply : aplica una serie de comandos
a un thread
● Se pueden fijar breakpoint por thread break
spec thread n
Ejemplo
● Recompilar el cliente y servidor de corba con
la opción -g
● g++ g eg2_impl.cc echoSK.cc o servidor_debug
lomnithread lomniORB4 I.
● Lanzar el servidor en background
● Lanzar el gdb contra ese proceso y poner un
breakpoint en Echo_i::echoString
● Lanzar el cliente en otra ventana
Comandos gdb
● print : imprime una expresión
● shell comando : ejecuta un comando en la
shell
● make argumentos : ejecuta un make
● info break : información sobre breakpoints
● help : ayuda
● show : muestra estado gdb
Depuración remota
● Desde la versión 5.3 existe la depuración
remota en gdb
● Hace uso de gdbserver
● Es posible ejecutar el código sin los
símbolos de depuración mientras se
disponga de ellos en local
Depuración remota (2)
● Compilar gdb para la plataforma elegida
● Compilar gdbserver (bajo
gdb/gdbserver) con el compilador
cruzado
● Transferir gdbserver al sistema elegido
● Ejecutar gdbserver foo:1234 programa
● En el sistema de desarrollo ejecutar gdb
programa
Depuración remota (3)
● Dentro del gdb
– target remote foo:1234
● A partir de ese momento ya se ejecutan los
comandos de depuración en remoto.
Ejemplo
● Depurar, dos a dos, en remoto el servidor
corba
Técnicas de depuración
● Código de depuración en tiempo de
compilación
#ifdef DEBUG
fprintf (stderr,”myvar = %d\n”,myvar);
fflush(stderr);
#endif
● Añadir -DDEBUG a la línea de compilación
provoca que se active la depuración
Consejos
● Enviar los mensajes a stderr
● Hacer flush después de cada mensaje
● Utilizar un simbolo propio, mejor que
DEBUG, incluso múltiples símbolos por cada
zona de depuración
● Crear macros para evitar los ifdef
#ifdef DEBUG
#define DPRINT(msg) fprintf(stderr,msg)
#else
define DPRINT(msg)
Opciones macros
● #define DPRINT(stuff) fprintf stuff
● requiere cambiar la llamada
● #define DPRINT(msg,...)
fprintf(stderr,mesg,__VA_ARGS__)
● Solo compatible compiladores C99
Consejos
● Evitar las macros de expresiones
● Reordenar el código para mejorar la
visibilidad en depuración
● Emplear enumeraciones en lugar de macros
● Crear funciones auxiliares de depuración
● Evitar las uniones cuando sea posible
Herramientas de depuración
● librería dbug
● Depuradores de asignación de memoria
– mtrace
– Electric Fence
– dmalloc
– Valgrind
– Otros depuradores
El problema
● Pérdida de memoria: memoria asignada e
imposible de alcanzar
● Memoria sin liberar
● Liberaciones incorrectas
● Uso de memoria ya liberada
● Saturación de memoria
● Uso de memoria sin inicializar
mtrace
● Funciona en sistemas Linux con glibc
● incorpora dos funciones para habilitar y
deshabilitar el seguimiento de memoria
● #include <mcheck.h>
● void mtrace(void);
● void muntrace(void)
● La variable de entorno MALLOC_TRACE
indica un archivo donde guargar la
información
Ejemplo
#include <stdio.h>
#include <stdlib.h>
int main (int argc, char **argv)
{
char *p;
int i;
p=malloc(30);
strcpy(p,"not 30 bytes");
printf ("p = <%s>\n",p);
if (argc==2) {
if (strcmp(argv[1],"b")==0)
p[42]='a';
Comentarios de: AREA 2 : Depuración y optimización - Curso Linux (0)
No hay comentarios