Quelques mots sur GDB




GDB (The Gnu Debugger) est un debugger fournit en standard dans toute distribution Linux. Il permet de tracer pas à pas l'évolution d'un programme. Pour celà, il offre à l'utilisateur la possibilité de suivre l'évolution des différentes variables et de placer des points d'arrêt.

Pour pouvoir débugger un programme C, il faut le compiler avec l'option -g de gcc (le caractère % symbolise le prompt de votre interprète de commande):

% gcc -g prog.c

On lance alors le debugger comme suit:

% gdb a.out

On obtient alors le prompt de gdb:

(gdb)

Voici une liste (non exhaustive) des commandes utiles pour suivre l'évolution du programme:
 

  • list : permet d'afficher la liste numérotée des lignes du fichier source . Seul quelques lignes sont affichées, il faut faire appel plusieurs fois de suite à cette commande pour  afficher la totalité du source.

  •  
  • list n : affiche un ensemble de lignes du fichier source centré autour de la ligne numéro n.

  •  
  • break n : place un point d'arrêt sur la ligne numéro n. A chaque fois que le programme sera exécuté, il s'arrêtera sur cette ligne.

  •  
  • watch expression : interrompt l'exécution du programme, à chaque fois que l'expression est modifiée dans le programme. Le debugger indique alors la nouvelle valeur de l'expression, ainsi que le numéro de la ligne ayant provoqué ce changement.

  •  
  • display expression : place une observation sur l'expression. A chaque point d'arrêt, la valeur de l'expression sera donnée. Un numéro est affectée à l'expression mise en observation.

  •  
  • display : affiche la valeur de toutes les expressions en observation.

  •  
  • run : lance l'exécution du programme.

  •  
  • c: si le programme est arrêté sur un point d'arrêt, permet de continuer son exécution

  •  
  • next: si le programme est arrêté sur un point d'arrêt, permet d'exécuter l'instruction suivante. Si cette dernière est un appel de fonction, la fonction est exécutée dans sa totalité.

  •  
  • step:  si le programme est arrêté sur un point d'arrêt, permet d'exécuter l'instruction suivante. Si cette dernière est un appel de fonction, la première instruction de la fonction est exécutée et le debugger se met en attente.

  •  
  • undisplay : annule toutes les observations.

  •  
  • undisplay n : annule l'observation de l'expression numéro n.

  •  
  • delete : annule tous les points d'arrêt.

  • delete n : supprime le point d'arrêt numéro n.

    Un petit exemple (pour illustrer quelques unes des possibilités de gdb)

    Considérons le programme somme.c qui initialise aléatoirement un tableau de 10 entiers compris entre 0 et 100 et qui calcule leur somme. Dans ce qui suit on mettra en italique ce qui s'affiche à l'écran suite aux différentes commandes exécutées
    1.  Compilation du programme:

    2. % gcc -g somme.c
       
    3. On lance le debugger:

    4. % gdb a.out

      (gdb)
       

    5. Listons le programme source correspondant:

    6. (gdb) list

      1  #include <stdio.h>
      2  #include <stdlib.h>
      3
      4       int T[10];
      5       int i, somme;
      6
      7       int main(void)
      8       {
      9         for (i = 0; i < 10; i++)
      10          T[i] =  rand() % 100;
       

    7. Listons la suite du programme:

    8. (gdb) list

      11        somme = 0;
      12        for (i = 0; i < 10; i++)
      13          somme = somme + T[i];
      14        printf("somme = %d\n",somme);
      15      }
       

    9. Nous allons placer un point d'arrêt sur la ligne 11 de façon à pouvoir observer la valeur de T à la sortie de la première boucle.

    10. (gdb) break 11

      Breakpoint 1 at 0x80484e4: file somme.c, line 11.
       

    11. Nous allons ensuite placer un point d'arrêt sur la ligne 13 de façon à pouvoir observer à chaque étape la valeur de i et de somme.

    12. (gdb) break 13

      Breakpoint 2 at 0x8048504: file somme.c, line 13.
       

    13. Nous plaçons maintenant une observation sur somme,  i et T.

    14. (gdb) display somme
      (gdb) display i
      (gdb) display T
       
       
    15. Nous pouvons lancer maintenant l'exécution du programme.

    16. (gdb) run

      Starting program: /home/......    ....../a.out

      Breakpoint 1, main () at somme.c:11
      11        somme = 0;
      3: T = {83, 86, 77, 15, 93, 35, 86, 92, 49, 21}
      2: i = 10
      1: somme = 0
       

      Nous sommes arrêtés sur le premier breakpoint en ligne 11. gdb affiche la prochaine instruction à exécuter (somme = 0) et la valeur des différentes expressions en observation. On remarque que somme vaut 0 alors que l'instruction n'a pas été exécutée. Ceci est du au fait que par défaut les varaibles globales sonr initalisées à 0.
       

    17. Lançons uniquement l'exécution de l'instruction suivante (la valeur de T ne nous intéresse plus).

    18. (gdb) undisplay 3
      (gdb) next

      12        for (i = 0; i < 10; i++)
      2: i = 10
      1: somme = 0
       

    19. Nous sommes sur l'iinstruction suivante, c'est pourquoi i vaut toujours 10. Lançons mainetnant la suite de l'exécution du programme.

    20. (gdb) c

      Continuing.

      Breakpoint 2, main () at somme.c:13
      13          somme = somme + T[i];
      2: i = 0
      1: somme = 0
       

    21. Nous sommes sur le deuxième point d'arrêt, l'instruction à exécuter est somme = somme + T[i]. Les variables somme et i ont été initialisées à 0. Continuons l'exécution.

    22. (gdb) c

      Continuing.

      Breakpoint 2, main () at somme.c:13
      13          somme = somme + T[i];
      2: i = 1
      1: somme = 83
       

    23. Nous sommes à nouveau sur le point d'arrêt numéro 2. i vaut 1 et somme vaut 83 puisqu'à l'étape précédente (i=0) on a ajouté T[0] à somme. Tout à l'air de bien se passer,  plutôt que d'avoir à relancer encore 9 fois l'exécution du programme, nous allons supprimer le point d'arrêt 2 , en mettre un à la sortie de la boucle et continuer l'exécution du programme.

    24. (gdb) delete 2
      (gdb) break 14

      Breakpoint 3 at 0x8048528: file somme.c, line 14.

      (gdb) c

      Breakpoint 3, main () at somme.c:14
      14        printf("somme = %d\n",somme);
      2: i = 10
      1: somme = 637
       

    25. Nous sommes à la sortie de la boucle, le résultat est 637. Un doute ? Affichons le contenu de T.

    26. (gdb) print T

      $1 = {83, 86, 77, 15, 93, 35, 86, 92, 49, 21}
       

    27. Pas de calculaltrice sous la main ? Mauvais en calcul mental ? Demandons à gdb de vérifier pour nous.

    28. (gdb) print T[0]+T[1]+T[2]+T[3]+T[4]+T[5]+T[6]+T[7]+T[8]+T[9]

      $2 = 637
       

    29. Il ne nous reste plus qu'à terminer l'exécution du programme

    30. (gdb) c

      Continuing.
      somme = 637

      Program exited with code 014.
       

    31. Nous pouvons quitter le debugger.

    32. (gdb) quit