Débogage avancé/Travail pratique/Débogage à la volée
But de ce TP
modifierLe débogage de l'exécution d'un programme peut ne pas avoir été anticipé. Heureusement, il est possible de commencer le débogage en cours de route.
Attention, certains systèmes Linux (dont Ubuntu) sont configurés par défaut pour vous empêcher de faire cela. Il faudra en modifier la configuration pour pouvoir faire ce TP.
Le code à déboguer
modifierAttention: ce code tourne en boucle ! Créer un fichier bug_loop.c contenant le code suivant.
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <unistd.h>
typedef struct elem {
struct elem *next;
} Elem;
uint64_t list_length(Elem *h) {
uint64_t l = 0;
while (h != NULL) {
h = h->next;
l++;
}
return l;
}
int main(int argc, char *argv[static argc+1) {
(void)argc;
int mypid = getpid();
printf("My PID is: %d. Catch me with 'gdb %s %d' !\n", mypid, argv[0], mypid);
// build a short and smallcircular list in stack
Elem a;
Elem b = {.next = &a};
a = (Elem){.next = &b};
Elem *head = &a;
// infinite loop in list_length
printf("list length: %lu\n", list_length(head));
return EXIT_SUCCESS;
}
Pour éviter des mésaventures désagréables, comme vider la batterie de son ordinateur portable, nous conseillons de toujours lancer ce programme en limitant son temps d'exécution (ici à 300 secondes, 5 minutes max). Attention à bien mettre les parenthèses, sinon vous risquez de limiter aussi tous les processus que vous lancerez dans le même terminal.
$ ( ulimit -t 300; ./bug_loop ) &
Les consignes
modifierLe programme tourne donc à l'infini. Vous avez donc tout le temps pour
l'attraper au vol. Pour faciliter votre travail, il indique aussi
comment l'attraper au vol avec votre débogueur. L'alternative est
d'obtenir le PID du processus avec la commande ps
.
Après l'avoir attraper, vous changer la valeur d'une de ces variables à la volée pour lui permettre de terminer proprement.
- Lancer le programme en tâche de fond en limitant son temps d'exécution à 5 minutes (300 secondes).
- Demander à votre débogueur de s'accrocher au processus en train de tourner avant qu'il soit fini.
- Afficher le code à proximité de l'arrêt.
- Avancer l'excution pas-à-pas dans la boucle while jusqu'à la ligne
l++
. - Changer la valeur de h pour la mettre à 0 (NULL).
- Continuer jusqu'à la sortie de la fonction
- Continuer jusqu'à la terminaison.
Vous devriez avoir tapé les commandes suivantes (les affichages de GDB sont omis):
$ gcc -o bug_loop bug_loop.c -g -Wall -Wextra -fanalyzer
$ ( ulimit -t 300; ./bug_loop ) &
My PID is: 12345. Catch me with 'gdb ./bug_loop 12345' !
$ ps
[...]
12345 pts/3 00:00:01 bug_loop
[...]
$ gdb ./bug_loop 12345
[...]
(gdb) layout src
(gdb) next # nombre variable de next à faire (0-3) pour arriver à l++
(gdb) set variable h = 0 # change h
(gdb) finish # pour aller jusqu'à la fin de la fonction
(gdb) next # nombre variable de next jusqu'à la fin (3-5)
(gdb) next
(gdb) next # fin du processus au bout de 3 next dans cet exemple
(gdb) quit # rien à confirmer, le processus est déjà mort