gdb trouve la ligne qui fait planter
gdb est le débogueur du projet GNU : un programme qui lance votre programme et l’arrête pour vous montrer où il en est. Quand un programme C s’interrompt avec le message « Segmentation fault », gdb donne en quelques secondes la ligne fautive.
Une application de gestion de stock s’arrête sans autre explication chaque fois qu’on ajoute un article. Relire mille lignes prendrait la journée, alors que gdb indique la bonne ligne tout de suite.
À la fin de cette leçon
Remarque
Je peux trouver avec un débogueur la ligne où un programme plante.
Mots-clés
| Mot | Ce que ça veut dire | Exemple |
|---|---|---|
| Débogueur | un programme qui lance un autre programme et l’observe | gdb |
| Signal | un message que le système envoie à un processus | SIGSEGV |
| Erreur de segmentation | l’arrêt d’un programme qui touche une mémoire interdite | |
| Trace de la pile | la liste des appels de fonction en cours | |
| Point d’arrêt | une ligne où le débogueur arrête le programme |
Les cellules que les étudiants remplissent restent vides dans cet aperçu.
L’option -g garde les noms et les lignes
gcc supprime les noms de variables et de fonctions du programme final. Avec l’option -g, il y garde une table qui relie chaque instruction à sa ligne de C.
Ajoutez aussi -O0 pour ne pas optimiser : les lignes suivent alors l’ordre du fichier. Le programme ci-dessous a une fonction ranger qui écrit à une adresse reçue. main lui donne NULL.
Un programme qui écrit à l’adresse NULL
1 #include <stdio.h>
2 void ranger(int *cible, int valeur) {
3 *cible = valeur;
4 }
5 int main(void) {
6 int *p = NULL;
7 ranger(p, 6);
8 printf("fini\n");
9 return 0;
10 }Aller dans le dossier de travail
mkdir -p ~/c && cd ~/cAffichée ici, non exécutée. Créez un compte gratuit pour appuyer sur Exécuter et la saisir dans le terminal de votre propre labo.
Écrire le programme dans un fichier
printf '#include <stdio.h>\nvoid ranger(int *cible, int valeur) {\n *cible = valeur;\n}\nint main(void) {\n int *p = NULL;\n ranger(p, 6);\n printf("fini\\n");\n return 0;\n}\n' > plante.cAffichée ici, non exécutée. Créez un compte gratuit pour appuyer sur Exécuter et la saisir dans le terminal de votre propre labo.
Compiler avec les informations de débogage
gcc -g -O0 -o plante plante.cAffichée ici, non exécutée. Créez un compte gratuit pour appuyer sur Exécuter et la saisir dans le terminal de votre propre labo.
Compter les signaux reçus par le programme
gdb -batch -ex run ./plante 2>&1 | grep -c SIGSEGVAffichée ici, non exécutée. Créez un compte gratuit pour appuyer sur Exécuter et la saisir dans le terminal de votre propre labo.
La trace montre qui a appelé qui
La commande bt (backtrace) liste les appels en cours, du plus récent au plus ancien. Le cadre numéro 0 est la fonction où le programme s’est arrêté. Le cadre suivant est l’appelant, et ainsi de suite jusqu’à main.
Chaque ligne donne la fonction, ses arguments et la ligne du fichier. Le Run affiche seulement la fin de chaque ligne, car le début contient une adresse qui change.
Lister les lignes de la trace
gdb -batch -ex run -ex bt ./plante 2>&1 | grep "^#" | grep -o "at plante.c:[0-9]*"Affichée ici, non exécutée. Créez un compte gratuit pour appuyer sur Exécuter et la saisir dans le terminal de votre propre labo.
Exemple travaillé : lire la trace
| Cadre | Fonction | Ligne | Ce que cela dit |
|---|---|---|---|
| 0 | ranger | 3 | Le plantage se produit en écrivant *cible |
| 1 | main | 7 | main a appelé ranger à cette ligne |
Les cellules que les étudiants remplissent restent vides dans cet aperçu.
print montre la valeur d’une variable
Une fois le programme arrêté, la commande print affiche une variable du cadre courant. Ici print cible donne 0x0, l’adresse zéro, et print valeur donne 6.
On a trouvé la cause : ranger écrit à l’adresse zéro. La ligne 7 de main lui a passé NULL.
Afficher les deux arguments au moment du plantage
gdb -batch -ex run -ex "print cible" -ex "print valeur" ./plante 2>&1 | grep '^\$'Affichée ici, non exécutée. Créez un compte gratuit pour appuyer sur Exécuter et la saisir dans le terminal de votre propre labo.
Un point d’arrêt arrête avant le plantage
On n’attend pas toujours le plantage. La commande break ranger pose un point d’arrêt à l’entrée de la fonction ranger. Le programme s’arrête là, avant d’écrire.
info args affiche alors les arguments reçus. On voit que cible est déjà 0x0 avant la ligne fautive.
Arrêter dans ranger et lire les arguments
gdb -batch -ex "break ranger" -ex run -ex "info args" ./plante 2>&1 | grep -E "^(cible|valeur)"Affichée ici, non exécutée. Créez un compte gratuit pour appuyer sur Exécuter et la saisir dans le terminal de votre propre labo.
Exemple travaillé : reconnaître un plantage
| Signal | Statut du shell | Cause la plus courante |
|---|---|---|
| SIGSEGV | 139 | Une adresse invalide, NULL ou une pile pleine |
| SIGFPE | 136 | Une division entière par zéro |
| SIGABRT | 134 | Le programme se tue lui-même après une erreur détectée |
Les cellules que les étudiants remplissent restent vides dans cet aperçu.
Erreur fréquente
Attention
Beaucoup de gens pensent que la ligne du plantage contient la faute. Elle montre seulement où le mal éclate. Dans notre exemple, la faute est à la ligne 7, où main passe NULL. Remontez la trace jusqu’à la ligne qui a donné la mauvaise valeur.