Déboguer son programme avec GDB

Formation

En Semi-présenciel Paris

Prix sur demande

Appeler le centre

Avez-vous besoin d'un coach de formation?

Il vous aidera à comparer différents cours et à trouver la solution la plus abordable.

Description

  • Typologie

    Formation

  • Méthodologie

    En semi-présentiel

  • Lieu

    Paris

Grâce à cette formation vous pourrez acquérir les connaissances nécessaires qui vous permettrons d’ajouter des compétences à votre profil et obtenir de solides aptitude qui vous offriront de nombreuses opportunités professionnelles.

Les sites et dates disponibles

Lieu

Date de début

Paris ((75) Paris)
Voir plan
7 Cité Paradis, 75010

Date de début

Consulter

Questions / Réponses

Ajoutez votre question

Nos conseillers et autres utilisateurs pourront vous répondre

À qui souhaitez-vous addresser votre question?

Saisissez vos coordonnées pour recevoir une réponse

Nous ne publierons que votre nom et votre question

Les Avis

Le programme

Introduction du cours

Ah, la programmation ! Qui ne s'est jamais débattu pendant des heures avec des plantages biscornus et impossibles à cerner ? Qui ne s'est jamais retrouvé obligé de remplir son code d'instructions de "debug", affichant ici et là diverses variables, histoire de pouvoir s'assurer de leur contenu ? Que serait la vie d'un développeur sans ce temps perdu, passé à maudire de tous les noms (et de toutes les onomatopées) les messages de plantage déversés par un programme un peu trop fougueux ?

Heureusement, il existe de nombreux logiciels dits de "debugging". Je vous propose, parmi la flopée de prétendants, de nous lancer dans la conquête de GDB, le debogueur de GNU.

GDB est portable, il fonctionne donc aussi bien sur UNIX/Linux que sur Windows ou sur MacOS. Ce tutoriel a été développé sous Linux.

Démarrer une session GDBInstallationSous Linux/Unix

GDB est disponible dans la plupart des dépôts et peut également être téléchargé directement sur le site officiel.

Si vous ne savez pas comment installer un programme depuis les dépôts, référez-vous au tutoriel du site, dans la partie Linux : "Installer des programmes avec apt-get".

Si GDB n'est pas dans vos dépôts, téléchargez les sources de la dernière version et compilez-les. Ça devrait se faire facilement, je vous donne les étapes principales, si vous rencontrez un problème référez-vous au site de votre distribution pour trouver comment compiler (rem. remplacez les X.X par les numéros de la dernière version stable) :

wget http://ftp.gnu.org/gnu/gdb/gdb-X.X.tar.gz tar -xvvf gdb-X.X.tar.gz cd gdb-X.X.tar.gz ./configure make make installLancement d'une session

GDB fonctionne sur le principe d'une invite de commandes. Pour démarrer une session, on lance simplement GDB en lui passant éventuellement des paramètres. Le moyen le plus courant de démarrer une session est de préciser l'exécutable qu'on veut débugger en paramètre :

gdb program

Lorsqu'un programme plante, vous avez certainement déjà lu "(core dumped)". Cela signifie en fait que le système a enregistré dans un fichier une copie de ce qui se trouvait en mémoire au moment du plantage (la zone du programme qui a planté uniquement). C'est parfois utile pour faire des vérifications, mais ce n'est pas simple et donc nous n'en parlerons pas ici. Cependant, sachez que GDB permet de spécifier le nom de ce fichier comme second argument :

gdb program dumpfile

Parfois on souhaite déboguer un exécutable qui est déjà lancé, ce qu'on peut faire en précisant en second paramètre l'identifiant du processus. En général pour voir la liste des processus lancés, on utilise la commande ps (lisez la page man pour plus d'informations). Attention cependant, il ne doit pas y avoir de fichier portant le même nom que l'id du processus, sinon GDB va utiliser ce fichier comme fichier de dump au lieu de se référer au processus (ce qui peut avoir des effets désastreux).

gdb program 1234

Lorsque vous lancez GDB, il commence par vous afficher quelques informations légales. Vous pouvez préciser de ne pas afficher ces informations avec le paramètre -silent (ou -quiet ou encore -q) :

gdb program -silent

Une fois que vous avez lancé GDB, vous devez entrer des commandes pour lui indiquer quoi faire. D'ailleurs, GDB ne lance pas l'exécution du programme tant que vous ne le lui indiquez pas. Une ligne de commande GDB commence par le nom de la commande, qui peut être suivi par des paramètres. Si vous validez une ligne blanche, GDB répète la commande précédente. Vous pouvez également utiliser des abréviations au lieu des noms complets des commandes. Vous pouvez également placer des commentaires, ceux-ci commencent par # et se terminent à la fin de la ligne (donc marquent la fin de la commande).

$gdb program -q (gdb) command params #comment ...

Comme dans un terminal, vous pouvez utiliser l'auto-complétion avec la touche TAB.

Obtenir de l'aide sur une commande

Vous pouvez obtenir des informations sur les commandes grâce à "help" (abr. "h"). Si vous ne précisez pas la commande, GDB affiche les catégories de commandes disponibles. De même, si vous précisez une catégorie de commandes, GDB vous affichera la liste des commandes. Enfin, si vous précisez une commande ou son abréviation, GDB vous affichera les informations la concernant.

$gdb -q (gdb) help List of classes of commands:   aliases -- Aliases of other commands breakpoints -- Making program stop at certain points data -- Examining data files -- Specifying and examining files internals -- Maintenance commands obscure -- Obscure features running -- Running the program stack -- Examining the stack status -- Status inquiries support -- Support facilities tracepoints -- Tracing of program execution without stopping the program user-defined -- User-defined commands   Type "help" followed by a class name for a list of commands in that class. Type "help all" for the list of all commands. Type "help" followed by command name for full documentation. Type "apropos word" to search for commands related to "word". Command name abbreviations are allowed if unambiguous.

Comme indiqué, vous pouvez également utiliser "help all" pour obtenir la liste des toutes les commandes (classées par catégories).

Pour effectuer une recherche dans l'aide, il suffit d'utiliser la commande "apropos" qui prend comme paramètre une chaine à rechercher :

(gdb) apropos exit q -- Exit gdb quit -- Exit gdb set history save -- Set saving of the history record on exit show history save -- Show saving of the history record on exitExécuter le programme

Maintenant que nous avons quelques bases, il est temps de nous lancer dans le véritable travail du débogueur.

Compiler avec les informations de débogage

Pour déboguer un programme, il est nécessaire de pouvoir obtenir certaines informations le concernant, comme le nom et le type des variables, ainsi que les numéros de lignes correspondant aux instructions. Pour pouvoir les obtenir, on doit le préciser lors de la compilation. La plupart du temps, il s'agit de l'option "-g", cependant, vous devriez vérifier dans la documentation de votre compilateur.

GCC et NASM, par exemple, permettent de compiler avec les informations de débogage :

$ g++ -g myprogram.cpp $ nasm -g myprogram.asmLancer l'exécution

Il est temps de passer à la phase qui nous intéresse, l'exécution du programme. Rien de plus simple, il s'agit de la commande "run" (abr. "r"). Vous pouvez lui passer autant de paramètres que vous le souhaitez, ils seront simplement passés comme paramètres au programme exécuté.

(gdb) run args ... (gdb)

Le programme s'exécute alors normalement, jusqu'à ce qu'il se termine. Dès qu'il a fini de s'exécuter, ou lorsqu'il rencontre une erreur, vous revenez à l'invite de commandes de gdb. Il existe une autre commande pour lancer le programme : "start", qui contrairement à "run", place un point d'arrêt (breakpoint) à l'entrée du programme. Pour un programme réalisé en C par exemple, ce point d'arrêt sera placé à l'endroit du main().
Il est important de noter que le point d'entrée n'est pas toujours la première chose exécutée dans un programme. En C++, les constructeurs d'objets globaux et statiques sont appelés avant le main(), dans une phase dite "d'élaboration". Nous verrons plus tard comment placer des points d'arrêt précis.
Comme pour "run", vous pouvez spécifier les paramètres du programme.

(gdb) start args ... (gdb)Contexte d'exécution

Lorsque vous démarrez un programme, il hérite de certaines propriétés : les variables d'environnement, les arguments de ligne de commande, et le dossier courant.
Le dossier courant, c'est le dossier dans lequel vous exécutez le programme. Il est utilisé par exemple lorsque vous ouvrez un fichier sans préciser de chemin, le programme regarde alors dans ce répertoire courant.
Les arguments de ligne de commande, c'est ce que vous ajoutez après le nom de l'exécutable pour le lancer (ex : "$ g++ monfichier.cpp", g++ est le nom de l'exécutable, et "monfichier.cpp" est un argument).
Enfin, les variables d'environnement sont des variables globales, accessibles par tous les programmes. On y retrouve par exemple la variable PATH, qui donne des chemins vers les répertoires où chercher les exécutables (par exemple, lorsque vous lancez "$ g++", le programme gcc se trouve dans un de ces répertoires).

L'ensemble de ces paramètres est appelé le "contexte d'exécution" d'un programme. Et bien entendu, vous pourriez avoir besoin (ou juste une folle envie) de modifier ces paramètres. GDB propose donc des commandes pour y accéder.

(gdb) show args
Affiche la ligne d'arguments actuelle du programme.

(gdb) set args arguments
Règle la ligne d'arguments à "arguments" (vous pouvez aussi passer les arguments comme paramètres à start ou run).

(gdb) show environment [variable]
ou (gdb) show env [variable]
Affiche les variables d'environnement. Si vous précisez un nom de variable (ex : PATH), seule cette variable est affichée.
Vous pouvez aussi utiliser "(gdb) show paths" pour afficher la variable PATH.

(gdb) set environment variable [=value]
(gdb) set env variable [=value]
Règle la valeur d'une variable "variable" à "value". Si vous ne donnez pas de valeur, celle-ci sera une chaîne vide.
Vous pouvez aussi utiliser "(gdb) path [newpath]" pour ajouter newpath à la liste des répertoires d'exécutables.

(gdb) unset environment variable
(gdb) unset env variable
Supprime la variable d'environnement "variable" (son contenu ne devient même pas une chaine vide, elle est complètement supprimée de la liste).

(gdb) pwd
Affiche le répertoire courant.

(gdb) cd directory
Règle le répertoire courant à "directory".

Les entrées et sorties

Si votre programme utilise les entrées et sorties standards, les opérations d'entrée et de sortie seront effectuées dans le même terminal que GDB. Vous pouvez, pour plus de clarté par exemple, changer le terminal du programme exécuté.

Vous pouvez savoir dans quel terminal vous êtes avec "$ tty". Si vous êtes déjà dans gdb, inutile d'en sortir :

(gdb) show inferior-tty
Affiche le terminal courant utilisé pour le programme exécuté.

(gdb) set inferior-tty terminal
(gdb) tty terminal
Règle le terminal courant pour l'exécution du programme à "terminal".

Exemple :

TERMINAL /dev/pts/2

(gdb) tty /dev/pts/3 (gdb) run (gdb)

TERMINAL /dev/pts/3

$ Sorties et entrées du programme exécuté par GDB...Stopper l'exécution

Vous pouvez décider de stopper l'exécution du programme en cours. Il suffit d'utiliser la commande kill :

(gdb) kill Kill the program being debugged? (y or n) y (gdb)Placer des points d'arrêt

Pour contrôler l'exécution d'un programme, on utilise des points d'arrêt. On donne à GDB une liste d'endroits où il doit faire une pause dans l'exécution. Cela permet par exemple de vérifier l'état d'une variable ou le contenu d'un registre. Comme nous l'avons vu plus tôt, il est possible de placer automatiquement un point d'arrêt au point d'entrée du programme, avec la commande "start". Cependant, si le programme comporte plusieurs milliers de lignes, nous n'allons pas faire tourner tout le programme au "pas à pas" (une instruction à la fois, nous verrons plus tard comment faire), nous allons plutôt placer des points d'arrêt aux endroits qui nous intéressent.

Il y a trois façons de préciser un point d'arrêt :

  • indiquer un endroit précis (fonction, ligne, fichier) ;

  • lors de la modification d'une variable (ou à sa lecture) ;

  • lorsqu'un certain événement se produit (création d'un nouveau processus, chargement d'une librairie, throw ou catch d'une exception, etc.).

Respectivement, ces trois types de points d'arrêt se nomment breakpoints, watchpoints (points de surveillance), et catchpoints (points d'interception).

Lorsque GDB interrompt le programme, il affiche la raison de l'arrêt, la ligne de l'instruction suivante (la prochaine qui sera exécutée) et l'invite de commande :

(gdb) r Starting program: main Breakpoint 3, main () at sample1.cpp:9 9           a = a / b; (gdb)

(gdb) info break [breaknum]
Affiche la liste des points d'arrêt. Si vous précisez un numéro (et non une position), vous ne verrez que les infos qui concernent ce point d'arrêt.

Les breakpoints

GDB s'arrête juste avant l'instruction qui suit le breakpoint. Cela signifie par exemple que si vous demandez à GDB de s'arrêter à la ligne 17, il va s'arrêter juste au début de la ligne, sans l'exécuter.

(gdb) break [position]
Si on ne donne pas de position, GDB s'arrêtera à la prochaine instruction qui sera exécutée. Sinon on peut spécifier l'endroit où le programme sera arrêté :

  • en donnant un numéro de ligne (break 123) du fichier courant ;

  • en donnant un décalage en lignes par rapport à la prochaine instruction (break +5 #s'arrêter 5 lignes après la prochaine instruction) ;

  • en donnant un nom de fichier et un numéro de ligne (break monfichier.cpp:123) ;

  • en donnant un nom de fonction (break ma_fonction) ;

  • en donnant un nom de fichier et de fonction (break monfichier.cpp:ma_fonction) ;

  • en donnant une adresse (break *adresse #adresse peut être un nombre, une variable, une expression...).
    Exemple : "(gdb) break *(0x80F523 + maVariable).

Remarque : en précisant une fonction, plusieurs breakpoints peuvent êtres placés, par exemple avec un programme écrit en C++ où on aurait surchargé la fonction.

(gdb) break [position] if condition
On peut aussi préciser une condition d'arrêt. GDB va alors évaluer (calculer) cette condition juste avant de s'arrêter, pour savoir s'il doit ou non continuer. Exemple :

(gdb) break 123 if a+b < 0

GDB arrêtera alors l'exécution du programme à la ligne 123 seulement si a+b est négatif. La condition est écrite avec la syntaxe du langage utilisé pour le programme.

Parfois, vous ne souhaitez vous arrêter qu'une fois (par exemple, seulement lors du premier appel à une fonction). Il suffit alors d'utiliser "tbreak" à la place de "break", en l'utilisant exactement de la même manière.

(gdb) clear [position]
Supprime le breakpoint correspondant à la position indiquée. Comme précédemment, ne pas indiquer de position suppose qu'il s'agit de l'instruction suivante.

Appeler le centre

Avez-vous besoin d'un coach de formation?

Il vous aidera à comparer différents cours et à trouver la solution la plus abordable.

Déboguer son programme avec GDB

Prix sur demande