"J'aime faire des erreurs, je ne
souhaite pas renoncer à l'agréable liberté de faire des erreurs."
Charles Chaplin
Prologue
Le but de cet article est de montrer quelque concepts de base aux utilisateurs
qui n'ont jamais utilisé de débogueur auparavant, ou bien qui l'ont utilisé et cherchent
un environnement graphique plus agréable pour ce travail quotidien. On peut écrire
beaucoup à propos des capacités et de la robustesse du débogueur décrit (gdb) toutefois
nous avons décidé de rester simple dans un but didactique, comme d'habitude :)
Qu'est ce qu'un débogueur?
(Basé sur une histoire vrai ;) ).
" Il était une fois un programmeur dont la seule façon de
trouver un bogue dans son code était:
/*Code*/
(...)
Boucle
changer_une_variable;
afficher_la_valeur_de_la_variable;
fin de boucle
(...)
Il était forcé d'insérer de nombreuses fois ces lignes dans son code source
afin d'inspecter les valeurs des variables du programme pendant l'exécution.
C'était une tâche difficile qui lui coûtait deux fois plus de travail que
d'écrire le programme(..)".
Qui ne s'est jamais trouvé dans une telle situation? Souvent il y a une erreur
dans notre programme, nous avons tout changé et essayé,. A ce point nous sommes
presque convaincu que "c'est la faute du compilateur" car il ne reste que peu de choses
à essayer. Un débogueur permet de contrôler l'exécution d'un programme pas à pas, de telle sorte
qu'il est facile d'examiner l'état des variables, leur définition, ce qui se
passerait dans certaines conditions, etc... Tout cela, encore une fois,
de manière itérative pendant que le code en cours de débogage s'exécute. Si cette
définition de piéton n'est pas très claire, j'espère la rendre plus transparente
au long de l'article.
Que se passerait il si le programmeur de notre histoire avait un débogueur nommé "spy"
qui lui permettrait les choses suivantes:
jose# spy mon_programme
et si après avoir appelé "spy" notre programmeur pouvait faire les choses
suivantes:
spy > exécute mon_programme " jusqu'à la ligne 50"
spy > montre moi la valeur de la variable <X>
spy > quel est le type de la variable <X>
Trés probablement à ce moment notre programmeur imaginaire sauterait
de joie parce qu'il aurait finalement trouvé la cause du bogue.
Il est clair que l'outil nommé "spy" a été très utile car il a laissé
le programmeur exécuter le programme à sa guise tout en examinant les valeurs
et les définitions de variables du programme. Ceci est bien un DEBOGUEUR,
grossièrement caricaturé bien sur.
Avertissement !!: les débogueurs ne peuvent fonctionner qu'avec des programmes
compilés avec l'option débogue, "-g" dans le cas du compilateur
GNU gcc.
Un outil de débogage est disponible pour tous les utilisateurs LINUX (et
sur beaucoup d'autres plates-formes). C'est GDB " Le Débogueur au
niveau source GNU". Il est disponible pour le même prix et avec
la même licence que le système d'exploitation que vous utilisez probablement
pour lire cet article, la Licence Publique Générale GNU. Il permet de
déboguer du code écrit en C, C++, Modula-2 et assembleur.
Il y a de fortes chances pour qu'il soit inclus dans la distribution
de Linux que vous utilisez. Sinon, changer de distribution ou procurez
vous les sources quelque part sur Internet où il est disponible à des
millions d'endroits ;).
Disons que vous avez téléchargé les sources dans votre répertoire /usr/src,
allez alors à "/usr/src/gdb-4.xxxx/gdb", tapez "./configure"
et changez de répertoire vers "doc". Là vous pouvez construire la
documentation en exécutant "make gdb.dvi;make refcard.dvi" les deux
fichiers sont facilement visualisables ou imprimables sur tout système Linux.
Qu'est ce que DDD?
Plutôt que de continuer avec une présentation détaillée du fonctionnement
de gdb et de ses commandes, il sera plus utile pour les novices de se familiariser
avec un environnement beaucoup plus agréable qui est "ddd" , ce qui signifie
Display Data Debugger.
L'environnement ddd fournit une interface plus conviviale et plus facile
à configurer pour une session de débogage. Toutefois, remarquez que ddd n'est qu'une
interface graphique qui coiffe gdb, et que par conséquent, ce dernier est nécessaire
à un son fonctionnement correct. En fait, ddd permet à l'utilisateur de manipuler gdb
directement si nécessaire. D'autres débogueurs peuvent être manipulés avec ddd comme
dbx et xdb.
Une bonne source d'information sur ddd est
http://www.cs.tu-bs.de/softech/ddd/
et si vous utilisez Red Hat, les sources peuvent être trouvées en format .rpm. Il peut y avoir
deux versions de ddd, une compilé dynamiquement avec la bibliothèque Motif
et l'autre statiquement. La version statique est pour les utilisateurs qui ne possèdent pas
la bibliothèque Motif
J'ignore volontairement la configuration de ddd vis à vis de LESSTIF
(http://www.lesstif.org),
Je ne connais pas l'état d'avancement de lesstif, une implantation gratuite de la bibliothèque
graphique Motif. Il n'y a pas si longtemps, ddd ne se compilait et ne marchait avec lesstif
que grâce à un patch; je l'ai utilisé sur un noyau 1.2.13 avec lesstif 0.75 (Je pense ;).
Vous pouvez vérifier sur le site du projet lesstif l'avancement de ce projet.
Arrivés au point d'exécuter ddd, on obtient :
Figur2 1. Ecran principal de ddd
IL y a trois façons différentes d'appeler ddd; la précédente et
les deux suivantes:
ddd <program> core
ddd <program> <process_id>
Le fichier nommé "core" est produit chaque fois qu'un programme se plante
et il contient des informations utiles à propos du statut du programme
au moment de l'apparition de l'erreur. Si votre système ne génère pas de
"core dumps" vérifiez les variables d'environnement du core ('ulimit -a'
les montre toutes, et 'ulimit -c <value>' définit la taille maximale
d'autres valeurs intéressantes).
Le proccess id permet d'inspecter le programme en cours
d'exécution.
L'environnement graphique de ddd permet toujours d'exécuter une tâche
de plusieurs manières; je ne peux pas toutes les décrire, simplement
les plus simples et les plus directes. Notez aussi que la fenêtre inférieure
de la console principale ddd affiche une liste de toutes les transactions
effectuées par ddd. Cette fenêtre peut être très utile pour apprendre le
fonctionnement de gdb à partir de la ligne de commande.
L'environnement Graphique
La Figure 1 montre que la fenêtre principale est divisée en trois.
La partie inférieure correspond à la une "pure" console de débogage
(gdb dans notre cas) ou l'on peut saisir directement des commandes gdb
comme si l'on n'avait pas l'interface ddd. Le milieu affiche le code source
du programme, et la partie supérieure est une interface graphique dédiée aux
variables et objets du programme. Finalement, la barre d'outils est une
fenêtre flottante qui contrôle et exécute les commandes de ddd.
En plus de la fenêtre principale, il existe une fenêtre d'exécution
pour le processus en cours et une autre pour le code source du programme
à déboguer. Les deux sont optionnelles.
ddd est livré avec de multiples aides qui fournissent à l'utilisateur
les informations nécessaires à tout moment pendant une session de débogage.
Par exemple, une boite de dialogue apparaît toujours quand le curseur se
déplace au dessus d'une variable ou d'un des boutons de l'interface. Cette boite
de dialogue donne des informations pertinentes sur l'objet concerné.
La partie inférieure le la fenêtre principale a aussi la ligne d'état ddd
qui indique la commande en cours d'exécution et son statut. A droite,
on trouve un menu contextuel avec toute l'aide disponible. Une aide
supplémentaire est disponible avec la touche F1 et en sélectionnant
un sujet dans la fenêtre flottante. Enfin, on peut taper dans la console
gdb (la partie inférieure) la commande "help" pour obtenir une aide
générale sur le débogueur ou des informations spécifiques sur une de
ses commandes.
Par défaut, l'interface ddd propose une fenêtre principale divisée en
trois. Le menu "Préférences" permet d'avoir une interface ddd avec trois
fenêtres séparées à la place.
Figure 2. Aide pour le menu "File"
Commencer par le Bas
La "DDD:Debugger Console" est le bon endroit pour faire nos premiers pas
avec le débogueur; les utilisateurs expérimentés de gdb peuvent facilement manoeuvrer ddd de là.
D'après mon expérience, il est utile de surveiller ce qui se passe sur la console
du débogueur au moment du lancement de commandes par le biais de l'interface graphique. L'option
"Commands->Command History" permet de voir la liste des commandes précédentes dans
une fenêtre séparée.
Pour en savoir plus sur les possibilités et les spécificités de DDD, il est préférable de
se référer directement à la documentation originale. Voici tout de même comment réaliser quelques
tâches simples directement depuis le débogueur.
Tâches Générales
Le code source d'une session de débogage peut être chargé depuis la ligne de commande ddd
ou au moyen de l'option "File" du menu; le contenu du fichier source apparaît
dans l'emplacement correspondant. A partir de ce point, on peut naviguer dans le code source
examiner les valeurs et les types des variables, exécuter le programme tout en contrôlant son
exécution...
La sortie du programme peut être suivie dans une fenêtre d'exécution
(Options -> Run in Execution Window ), ou sur la console du debogueur
(cette méthode ne fonctionnera pas si le programme est conçu pour tourner avec
Motif ou une autre bibliothèque graphique).
En plaçant le curseur sur une variable dans le code source, vous verrez sa valeur
courante sur la ligne d'état de ddd. En appuyant sur le bouton droit de la souris, le menu
suivant apparaît:
Ce menu permet d'inspecter la valeur de la variable "fname",
dans la fenêtre inférieure ("drawing area "), qu'il s'agisse d'une
variable réelle ou seulement d'un pointeur (une variable contenant une
adresse mémoire d'une autre variable, pas sa valeur). De plus,"What is"
montre la structure ou le type de cette variable; Lookup permet de rechercher
d'autres occurrences de cette même variable. Finalement Break at et Clear at
autorisent la manipulation des points d'arrêt (breakpoints) dont nous allons
brièvement parler.
Un certain nombre d'options sont aussi disponibles dans la barre de boutons
sous la zone du code source. Il suffit de taper le nom du paramètre souhaité dans
la boite vide de gauche de choisir l'action appropriée.
Uu point d'arrêt (break-point) laisse le programme s'exécuter jusqu'à
une ligne donnée; l'exécution s'arrête alors et l'utilisateur peut inspecter les
valeurs de variables jusqu'à ce point, continuer l'exécution pas à pas à la main,
passer en revue les cheminements (threads).... etc. En général, il faut prendre en compte
le fait qu'en l'absence de points d'arrêts dans le programme, celui-ci termine
normalement sont exécution ou se plante à cause d'un bogue, il est alors trop tard
pour décider d'une action d'inspection du programme; il est nécessaire de déboguer
le programme "pendant son exécution".
Pour placer un point d'arrêt, procéder comme suit:
- Amener le curseur à gauche de la ligne où il doit être placé, appuyer sur le
bouton droit et choisissez Set Breakpoint ou Set Temporary Breakpoint.
La différence entre ces deux options réside dans le fait que le second est effacé
après le premier passage, tandis que le premier n'est effacé que par la commande
appropriée (L'auriez vous deviné? :) ).
- Appuyer sur le bouton "Break at ()" dans la fenêtre du code source.
- Tapez "break <numero_de_ligne>" dans la console du débogueur.
- Choisissez dans le menu Source->Edit Breakpoints, ceci ouvrira
aussi une fenêtre pour le contrôle de cet utilitaire:
Sur la figure, vous pouvez remarquer deux points d'arrêt aux lignes 70 et 71 du code source,
le symbole des points d'arrêt parle de lui même.
Le menu suivant sert à gérer les points d'arrêt:
- Avec l'option Condition des points d'arrêts
conditionnels peuvent être placés. Dans ce cas, le programme
ne s'arrêtera que si la condition est vérifiée au moment
où l'exécution atteint la ligne du point d'arrêt. Une autre
sorte de condition est Ignore Count , est vraie
lorsque la ligne du point d'arrêt est atteinte <n> fois.
Par exemple, elle peut être utilisée pour arrêter le programme
après la 15ième itération d'une boucle.
Une fois que le programme s'est arrêté à un point d'arrêt, on peut inspecter
la valeur d'une variable du programme en utilisant les commandes des menus associées.
Pour mémoire, toutes ces fonctions sont situées dans le menu principal (c'est à dire
menu Data).
- Pour contrôler l'exécution, on utilise la boite de boutons qui lui est dédiée
exclusivement. Elle ses située dans le coin supérieur droit de la fenêtre principale.
On distingue parfaitement le parallèle qui existe entre la boite
de boutons et la barre de menu.
On peut démarrer et arrêter le programme, et si l'on utilise
la barre de menu il est possible de fournir certains paramètres
au programme au travers d'une boite de dialogue. Step exécute
les lignes une par une (pas à pas), autrement dit, s'il y a un appel
de fonction, le débogueur ira au début de cette fonction et attendra la
commande Step suivante. Par contre, la commande Next
exécute un appel de fonction comme une seule instruction.
Continue permet de continuer l'exécution d'un programme
arrêté après un point d'arrêt. Kill, Interrupt et Abort sont utilisés
pour interrompre l'exécution du programme.
La fenêtre d'affichage des données est probablement la caractéristique
la plus intéressante de cet outil graphique. On y voit graphiquement
la structure et le contenu des données ainsi que les dépendances entre elles.
Dans l'exemple suivant: un tableau (Argumentos) et quatre de ses éléments.
Cette fenêtre peut afficher une grande variété d'informations, voyez
le menu Data->More Status Displays , où l'on peut configurer
tout ce que l'on souhaite voir dans la fenêtre des données. Dans l'exemple
précédent, on peut aussi afficher le contenu des registres du processeur,
les bibliothèques dynamiques nécessaires et l'état d'exécution du programme:
Le Mot de la Fin
L'environement ddd peut être personnalisé depuis le même programme
avec le menu Options->Preferences, et aussi par la méthode classique des
ressources des applications Motif (fichier $HOME/.dddinit). La description de
toutes les ressources personnalisables et leur utilisation sort du cadre de cet
article
Il est fortement conseillé de lire le manuel fournit avec ddd
(ddd.ps) et celui du débogueur ("Debugging with GDB").
Néanmoins, l'utilisateur un peu curieux apprendra rapidement par lui
même. Il suffit de déboguer un code bien connu pour découvrir toutes les
possibilités de débogage.
Pour finir, toutes mes excuses si j'ai commis des erreurs dans
l'article :)
|
|