Déboggage sous GDB

Par Deimos le 05-01-2007



Ce tutorial décrit rapidement toutes les commandes nécessaires à savoir débogger sous GNU/Linux



Sommaire :
I. Introduction
II. Breakpoints
III. Commandes générales
IV. Deboggage avec fichier core


I. Introduction

     Ce tutorial a pour but de vous faire connaitre les commandes utiles (le plus couramment) lors du déboggage d'exécutable sous GNU/Linux. Il n'a pas le but d'être extrèmement exhaustif, il ya la documentation officielle de gdb pour ça =)


     Tout d'abord, avant de vouloir débugger son exécutable avec gdb, il faut l'avoir compilé avec les symboles de déboggage. Avec gcc, c'est l'option -g :


code_header shell :
spacer
$ gcc -g -o code code.c



     Ensuite, pour lancer un exécutable avec gdb puis stopper son exécution et quitter gdb :


code_header gdb :
spacer
(gdb) run
Starting program: /home/deimos/exemple
(gdb) kill
Kill the program being debugged? (y or n) y
(gdb) quit



II. Breakpoints

Il y a différentes méthode pour poser un breakpoint sous gdb ; ceci se fait avec la commande break, abrégée b :
     - b nom_fonction : pose un breakpoint au début de la fonction nommé
     - b ligne : pose un breakpoint au numéro de ligne donné du code source
     - b *adresse : pose un breakpoint à l'adresse donnée (exemple : b*0x08048384)
     - b : pose un breakpoint sur la prochaine instruction

     Note : Si l'exécutable provient de plusieurs fichiers sources, alors il est nécessaire de spécifier le nom du fichier source avant le numéro de ligne ou du nom de la fonction, selon la syntaxe : nom_fichier:num_ligne ou nom_fichier:fonction.

     Pour obtenir les informations sur les breakpoints, on utilise la commande info :


code_header gdb :
spacer
(gdb) info breakpoints
Num Type           Disp Enb Address    What
1   breakpoint     keep y   0x080483cd in foo at vuln.c:5
        breakpoint already hit 1 time
2   breakpoint     keep y   0x0804842e in main at vuln.c:16
3   breakpoint     keep y   0x0804843d in main at vuln.c:19
4   breakpoint     keep y   0x080483ff in main at vuln.c:12
(gdb) disable 2
(gdb) info breakpoints
Num Type           Disp Enb Address    What
1   breakpoint     keep y   0x080483cd in foo at vuln.c:5
        breakpoint already hit 1 time
2   breakpoint     keep n   0x0804842e in main at vuln.c:16
3   breakpoint     keep y   0x0804843d in main at vuln.c:19
4   breakpoint     keep y   0x080483ff in main at vuln.c:12
(gdb) delete 1
(gdb) info breakpoints
Num Type           Disp Enb Address    What
2   breakpoint     keep n   0x0804842e in main at vuln.c:16
3   breakpoint     keep y   0x0804843d in main at vuln.c:19
4   breakpoint     keep y   0x080483ff in main at vuln.c:12



Comme on le voit sur l'exemple ci-dessus, on peut supprimer ou activer/désactiver les bp posés avec ces commandes :
     - disable x : désactive le breakpoint de numéro x (dans la liste des bp de la commande info)
     - enable x : active le breakpoint de numéro x (dans la liste des bp de la commande info)
     - delete x : supprime le breakpoint de numéro x (dans la liste des bp de la commande info)
     - delete : supprime tous les breakpoints


III. Commandes générales

     - disass fonction : affiche le code assembleur de la fonction
     - bt -n : affiche les n frames au sommet de la stack
     - si / ni / step / next /s / n
     - p var : affiche la variable var de la fonction en cours (spécifier fichier ou fonction)
       p $reg : affiche le registre reg. Exemple : p $esp
       On peut spécifier à la commande p un format de sortie, selon la syntaxe : p/x var.
       Voir la note ci-dessous pour les formats.
     - info registers : affiche les registres (eax, ebx, ...)
     - x/nfu adresse : affiche n octets de la mémoire à l'adresse désirée, au format f
       et d'unité b (voir note pour les formats et unités)

Note : Formats de sortie : x(hexa), d(décimal signé), u(décimal non-signé), c(ascii), o(octal),... Unités : b(byte, 1 octet), h(halfword, 2octet), w(word, 4octets), g(giant word, 8octets).


IV. Deboggage avec fichier core

     Lorsqu'un exécutable crashe, par exemple après avoir reçu un signal SIGSEGV (Segmentation fault/violation), il est possible de le debogger directement sous gdb afin de connaitre la raison du crash. Pour cela, il faut exécuter la commande :


code_header shell :
spacer
$ gdb -c core



     core est le fichier généré lors du crash. Si toutefois aucun fichier n'est généré, il suffit alors d'exécuter la commande ulimit :

code_header shell :
spacer
$ ./test
Segmentation fault
$ ulimit -c 100000
$ ./test
Segmentation fault (core dumped)



     Nous pouvons alors lancer gdb avec en paramètre le fichier core, puis exécuter la commande where pour savoir où en est le code, ainsi que toutes les autres commandes afin de visionner la stack, les registres, etc ;)