|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
GNU Debugger, également appelé GDB, est le débogueur standard du projet GNU. Il a été porté sur de nombreux systèmes type Unix, dont AmigaOS 4.1 et fonctionne pour plusieurs langages de programmation, comme le C, C++, Fortran, Ada, Objective-C, et le Go. Il fut écrit par Richard Stallman en 1988. 1. GDB - pourquoi vivre sans ? La méthode de débogage de base est le printf(). Alors, pourquoi ne pas l'utiliser et se casser la tête avec un débogueur ?
2. GDB - comment en profiter ? GDB a besoin d'informations pour vous indiquer la ligne en cours d'exécution et pour pouvoir afficher ou modifier une variable. Ces informations sont ajoutées à l'exécutable au moment de la compilation. GCC dispose de deux commutateurs ("switches") pour cela :
Cette option fournit les informations de débogage dans le format natif de votre système.
Cette option va produire de l'information dans le format le plus détaillé pour GDB. Dans le cas d'AmigaOS 4.1, c'est cette option qui nous intéresse. Le niveau de détail peut être spécifié, ce niveau allant de 1 à 3, le défaut étant 2 :
Bien que GDB soit un des rares débogueurs capable de s'en sortir avec des exécutables optimisés, il n'est pas recommandé d'activer les optimisations pour le débogage, donc pas d'option "-O". 3. GDB - peut-on en profiter ? Bon, j'ai vendu le bazar, il y a bien un GDB (6.3) disponible, mais à la date d'aujourd'hui (15 novembre 2009), avec une Sam440ep utilisant AmigaOS 4.1 et le SDK 53.15, GDB n'est pas pleinement opérationnel, il manque quelques fonctionnalités qui rendent le débogage bien moins facile (possible ?). Je vais donc faire le tour de ce qui est utilisable actuellement. 4. GDB - dans la pratique Dans la pratique, toutes les commandes de GDB sont abréviables. Pour obtenir la liste des commandes, utilisez la commande "help" qui affiche des catégories sur lesquelles on peut appeler à nouveau "help" pour obtenir la liste des commandes concernées, lesquelles commandes dévoilent leurs détails à l'aide de la même commande "help". Autre point pratique, la touche "Return" sans commande rappelle la commande précédente. 4.1 Chargement de GDB Il y a deux façons de charger GDB, en l'appelant directement avec l'exécutable à déboguer :
...ou en chargeant ensuite le fichier à déboguer :
Pour quitter, utiliser "quit" (q). 4.2 Lancement et passage de paramètres L'exécution est lancée à l'aide de la commande "run" (r) :
Si on a besoin de passer des paramètres sur la ligne de commandes, on les place derrière la comande "run" :
Anomalie : quand on relance plusieurs fois un programme sans quitter GDB, celui-ci nous dit qu'un programme est déjà en cours d'exécution avant de le lancer. Il ne faut pas le croire, ce sont des balivernes :
Point particulier : GDB garde les derniers arguments qu'on lui a fournis. Pour les voir, utiliser la commande "show args", pour s'en débarrasser, utiliser "set args". 4.3 Utilisation des points d'arrêt Les points d'arrêt peuvent être positionnés au moyen de la commande "break" (b) suivie d'un nom de fonction ou d'un numéro de ligne dans un fichier. On peut examiner les points d'arrêt avec "info breakpoints" (ib) :
Les points d'arrêts peuvent être retirés avec "clear" (cl) et leur localisation ou "delete" (d) et leur identifiant. Ils peuvent être désactivés et réactivés au moyen des commandes "disable" et "enable" suivies de leur identifiant. Si on désire positionner un point d'arrêt utilisé une seule fois, on utilise "tbreak" (tb) qui positionne un point qui sera effacé automatiquement la première fois qu'il sera atteint. Bon, GDB s'arrête sur un point d'arrêt, et après ? Ben pour repartir, il faut utiliser la commande "continue" (c). Problème, avec le SDK 53.15 d'AmigaOS 4.1 sur Sam440ep, dès que GDB s'arrête sur un point d'arrêt permanent, il oublie ensuite de s'arrêter sur quelque condition que ce soit, b, tb ou adv. Il reste donc la solution de ne travailler qu'avec des points d'arrêts temporaires ou des commandes "advance" abordées plus loin. 4.4 Exécution pas à pas S'arrêter sur un point d'arrêt et repartir c'est bien, s'arrêter et poursuivre au ralenti, c'est mieux. GDB propose deux types de commandes pas à pas, "next" (n) et "step" (s).
4.5 Exécution jusque... Pour contrôler l'exécution de notre programme, il y a encore la commande "advance" (adv) qui prend en argument une identification de ligne identique à la définition d'un point d'arrêt. On peut voir cette commande comme la combinaison du positionnement d'un point d'arrêt temporaire et la commande "continue". Bonne nouvelle, cette commande semble fonctionner presque correctement... à condition de ne pas utiliser un point d'arrêt permanent et à condition de ne pas jouer dans des boucles. 4.6 L'examen des variables 4.6.1 Le type des variables On peut demander à GDB de nous rappeler le type d'une variable avec la commande "ptype" (pt) :
4.6.2 Examen occasionnel Quand on a besoin d'examiner une variable, on utilise la commande "print" (p).
Bonne nouvelle, il existe également une commande "printf".
On peut également typer une variable à la volée si nécessaire ou spécifier le format d'affichage avec :
Quand on a besoin de suivre une variable au cours d'une exécution, la commande "display" (disp ) permet d'afficher le contenu d'une variable à chaque arrêt d'exécution.
4.6.4 La modification de variable Les variables peuvent également être modifiées à l'aide de la commande "set variable" abréviable par "set" (<expression>) :
4.6.5 La surveillance de variable La commande "watch" (wa) permet de surveiller une variable (ou une expression) et d'arrêter l'exécution si une instruction modifie la variable (ou vérifie l'expression), ce qui peut être très intéressant pour localiser la modification fortuite d'une variable. Bon, dans la pratique, ça ne fonctionne pas avec notre SDK, étonnant, non ? Il existe des variantes "rwatch" et "awatch" qui surveillent respectivement l'accès en lecture ou l'accès en lecture ou écriture, mais elles ne sont pas gérées par notre plate-forme. Bref, point de salut ici. 4.7 Visualisation du source La commande "list" (l) permet d'afficher 10 lignes centrées sur la ligne d'exécution courante. Les appels suivants à "list" affichent les 10 lignes suivantes et ainsi de suite. Pour remonter dans le source, on utilise "list -". Pour lister une ligne précise, on l'indique derrière "list". Pour se localiser, la commande "where" affiche une pile d'appel simplifiée.
4.8 La pile d'appel En plus de "where", la pile des appels de fonction en cours peut être affichée au moyen de la commande "backtrace" (bt).
Le niveau 0 est la fonction en cours (PrintArgs) qui a été appelée depuis le niveau 1 (main), et ainsi de suite. Les commandes "up" et "down" permettent de se déplacer dans la pile d'appel afin d'avoir accès au contexte de pile concerné, pour examiner les variables automatiques par exemple.
4.9 L'attachement à un processus L'attachement à un processus peut être très intéressant pour inspecter l'état d'un processus en cours d'exécution. Un exemple qui me vient à l'idée serait de s'attacher au processus d'un serveur Ftp pour le déboguer en direct. Bon, je n'ai pas réussi à m'attacher à un processus, là aussi pas de surprise. 5. En conclusion GDB est-il d'un grand secours en l'état actuel des choses ? Bonne question. On peut tenter un débogage à l'aide de points d'arrêts temporaires, de commandes "advance", d'affichage de variable et de modification de variable. Cela n'apporte pas beaucoup plus que des "printf()", mais ça permet d'adapter ce qu'on veut voir et où on veut aller pendant l'exécution du programme, sans avoir besoin d'arrêter, de modifier le source et de recompiler. Cela peut donc être un petit peu mieux que des "printf()" mais il y a des cas, comme les boucles, où GDB ne s'arrêtera que la première fois. Il faudra donc envisager un doux mélange de "printf()" et de débogage. Si maintenant on se demande si les développeurs disposent de bons outils pour mettre au point leurs développements, ma réponse est clairement : NON. A tître de comparaison, lorsque je développe sous Delphi, le débogueur intégré arrête sur la ligne ayant déclenché une exception. Si la cause ne saute pas aux yeux, j'inspecte la pile d'appel, je mets un point d'arrêt en amont, je relance le bazarre, arrivé sur mon point d'arrêt j'inspecte les variables intéressantes en m'approchant du point d'exception jusqu'à localiser l'anomalie. Dans la pratique, je localise la cause immédiatement ou en quelques minutes, ce qui me permet d'utiliser mon temps à concevoir plutôt qu'à chercher la fichue ligne qui a déclenché un bête accès mémoire illégal. Mon temps sur Amiga étant pris sur mon temps libre, j'ai encore plus besoin d'efficacité dans mes développements que pour mon boulot. Alors s'il vous plait, donnez nous des outils qui fonctionnent.
|