Sommaire Index Rechercher Liens A Propos
[LinuxFocus Image]
[Barre de Navigation]
  Nouvelles   Archives

Deboguer du Code avec ddd

par Jose Maria Laveda


Prologue

Qu'est ce qu'un débogueur?

Qu'est ce que DDD

L'interface Graphique

Commencer par le Bas

Le Mot de la Fin

"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 :)


Traduit par John Perr

Pour en savoir plus:
© 1998 Jose Maria Laveda
Ce site Web est maintenu par Miguel A Sepulveda.