GDB/fr: Difference between revisions
(Created page with "GDB") |
No edit summary |
||
(33 intermediate revisions by 2 users not shown) | |||
Line 1: | Line 1: | ||
<languages /> | <languages /> | ||
[https://www.gnu.org/software/gdb/ GDB] | [https://www.gnu.org/software/gdb/ GDB] (pour ''<u>G</u>NU Project <u>D</u>e<u>b</u>ugger'') est un débogueur pour investiguer des problèmes présents dans les logiciels. | ||
== Description == | == Description == | ||
Avec un débogueur, il est possible de trouver rapidement la cause d'un problème dans un logiciel. | |||
Le cas type d'utilisation est pour trouver [https://fr.wikipedia.org/wiki/Erreur_de_segmentation les erreurs de segmentation]. | |||
Si vous désirez trouver un problème de mémoire (par exemple, une | |||
[https:// | [https://fr.wikipedia.org/wiki/Fuite_de_m%C3%A9moire fuite de mémoire]), il est conseillé d'utiliser [[Valgrind/fr|Valgrind]]. | ||
== | == Cas d'utilisation == | ||
=== | === Trouver la cause d'une erreur de segmentation directement avec le débogueur === | ||
Dans cette section, le programme suivant est utilisé : | |||
{{ | {{File | ||
File | |||
|name= program.cpp | |name= program.cpp | ||
|lines=yes | |lines=yes | ||
Line 36: | Line 34: | ||
} | } | ||
}} | }} | ||
Ce programme génère une erreur de segmentation lorsqu'on l'exécute. | |||
{{Commands|g++ -g program.cpp -o program | {{Commands|g++ -g program.cpp -o program | ||
|./program | |./program | ||
Line 43: | Line 41: | ||
}} | }} | ||
On peut alors l'exécuter à l'intérieur du débogueur. Notez qu'on a compilé avec l'option <tt>-g</tt> pour permettre au débogueur de décoder les symboles et fournir davantage d'information sur la source du bogue. On exécute l'application à l'intérieur du débogueur comme suit : | |||
{{Command | {{Command | ||
|gdb ./program | |gdb ./program | ||
Line 58: | Line 56: | ||
| | | | ||
}} | }} | ||
Ici, l'erreur est causée par la ligne 15. Le code accède à l'indice 1000000, mais le tableau contient seulement 1000 éléments. | |||
=== | === Trouver la cause d'une erreur de segmentation avec un fichier <tt>core</tt> === | ||
Dans cet exemple, on utilise le programme de la section précédente, mais sans utiliser le débogueur directement. Ceci est utile pour un bogue qui se produit longtemps après le début de l'exécution du programme. | |||
Afin de trouver la cause de l'erreur de segmentation, il faut générer un fichier <tt>core</tt>. Pour ce faire, il faut activer la création de tels fichiers. | |||
{{Command|ulimit -c unlimited}} | {{Command|ulimit -c unlimited}} | ||
En exécutant à nouveau le même programme, un fichier <tt>core</tt> sera écrit. | |||
{{Commands|./program | {{Commands|./program | ||
Segmentation fault (core dumped) | Segmentation fault (core dumped) | ||
Line 74: | Line 72: | ||
}} | }} | ||
En utilisant l'exécutable <tt>programme</tt> et le fichier <tt>core</tt>, il est possible de tracer l'exécution jusqu'à l'erreur. | |||
{{Command|gdb -q ./program | {{Command|gdb -q ./program | ||
Reading symbols from /home/seb/program...done. | Reading symbols from /home/seb/program...done. | ||
Line 81: | Line 78: | ||
(gdb) core-file core.18246 | (gdb) core-file core.18246 | ||
[New LWP 18246] | [New LWP 18246] | ||
Core was generated by | Core was generated by './program'. | ||
Program terminated with signal 11, Segmentation fault. | Program terminated with signal 11, Segmentation fault. | ||
#0 0x0000000000400c17 in main (argc{{=}}1, argv{{=}}0x7fff2315c848) at | #0 0x0000000000400c17 in main (argc{{=}}1, argv{{=}}0x7fff2315c848) at | ||
Line 95: | Line 92: | ||
| | | | ||
}} | }} | ||
On obtient alors le même résultat qu'en ayant exécuté le code à l'intérieur du débogueur. | |||
=== | === Attacher le débogueur à un processus existant === | ||
Il est possible de déboguer un processus existant, par exemple une tâche qui s'exécute sur un nœud de calcul. Pour ce faire, il faut d'abord trouver le numéro du processus. | |||
{{Command|ps aux {{!}} grep firefox {{!}} grep -v grep | {{Command|ps aux {{!}} grep firefox {{!}} grep -v grep | ||
Line 104: | Line 101: | ||
}} | }} | ||
Ensuite, il est possible d'attacher le débogueur directement. | |||
{{Command|gdb attach 12691 | {{Command|gdb attach 12691 | ||
}} | }} | ||
Après avoir fait cette commande, beaucoup d'information sera imprimée. | |||
Plusieurs commandes de débogage sont disponibles. L'une des commandes utiles est <tt>backtrace</tt>, ou <tt>bt</tt>. | |||
Cette commande permet d'afficher la pile d'appels en cours. | |||
{{Commandes|prompt=(gdb)|bt | {{Commandes|prompt=(gdb)|bt | ||
#0 0x00000033646e99ad in poll () from /lib64/libc.so.6 | #0 0x00000033646e99ad in poll () from /lib64/libc.so.6 | ||
Line 135: | Line 132: | ||
A debugging session is active. | A debugging session is active. | ||
Inferior 1 [process 12691] will be detached. | |||
Quit anyway? (y or n) y | Quit anyway? (y or n) y | ||
Line 141: | Line 138: | ||
}} | }} | ||
== Utilisation plus avancée == | |||
== | Dans les sections précédentes, nous avons utilisé les commandes <tt>run</tt> et <tt>backtrace</tt>. Plusieurs autres commandes sont disponibles pour déboguer en mode interactif, soit en contrôlant l'exécution du programme. Il est par exemple possible de fixer des points d'arrêt sur des fonctions ou des lignes de code ou encore lors d'une modification d'une variable. Lorsque l'exécution est interrompue, il est possible d'analyser l'état du programme en affichant la valeur de certaines variables. Le tableau ci-dessous contient une liste des principales commandes. | ||
{| class="wikitable" style="font-size: 95%; text-align: center;" | {| class="wikitable" style="font-size: 95%; text-align: center;" | ||
|+align="bottom" style="color:#e76700;"|'' | |+align="bottom" style="color:#e76700;"|''Principales commandes de GDB'' | ||
! | | ! | Commande | ||
! | | ! | Raccourci | ||
! | Argument | ! | Argument | ||
! | Description | ! | Description | ||
Line 155: | Line 151: | ||
|r/k | |r/k | ||
| - | | - | ||
| | |débute/arrête l'exécution du programme | ||
|- | |- | ||
|where / backtrace | |where / backtrace | ||
|bt | |bt | ||
| - | | - | ||
| | |affiche la pile d'appel | ||
|- | |- | ||
|break | |break | ||
|b | |b | ||
|src.c: | |src.c:numero_de_ligne ou fonction | ||
| | |crée un point d'arrêt à la ligne de code ou à la fonction spécifiée | ||
|- | |- | ||
|watch | |watch | ||
| - | | - | ||
|variable | |nom de variable | ||
| | |arrête l'exécution lorsque la variable est modifiée | ||
|- | |- | ||
|continue | |continue | ||
|c | |c | ||
| - | | - | ||
| | |continue l'exécution après un point d'arrêt | ||
|- | |- | ||
|step | |step | ||
|s | |s | ||
| - | | - | ||
| | |exécute l'opération suivante | ||
|- | |- | ||
|print | |print | ||
|p | |p | ||
|variable | |nom de variable | ||
| | |affiche le contenu d'une variable | ||
|- | |- | ||
|list | |list | ||
|l | |l | ||
|src.c: | |src.c:numéro | ||
| | |affiche la ligne de code spécifiée | ||
|} | |} | ||
=== | === Afficher les structures de la STL === | ||
Par défaut, GDB n'affiche pas très bien le contenu des structures de la librairie standard du C++ (STL). Plusieurs solutions sont documentées [https://sourceware.org/gdb/wiki/STLSupport ici]. La solution la plus simple est probablement [http://www.yolinux.com/TUTORIALS/GDB-Commands.html#STLDEREF celle-ci], qui consiste à copier [http://www.yolinux.com/TUTORIALS/src/dbinit_stl_views-1.03.txt ce fichier] dans votre répertoire d'accueil, sous le nom <tt>~/.gdbinit</tt>. | |||
== | == Autres ressources == | ||
* [http://www.sourceware.org/gdb/ GDB | * [http://www.sourceware.org/gdb/ Site web GDB] | ||
* [http://oucsace.cs.ohiou.edu/~bhumphre/gdb.html GDB | * [http://oucsace.cs.ohiou.edu/~bhumphre/gdb.html Tutoriel GDB] | ||
* [http://goo.gl/rLPvR0 | * [http://goo.gl/rLPvR0 Document du TACC sur le débogage et le profilage] |
Latest revision as of 19:40, 15 July 2024
GDB (pour GNU Project Debugger) est un débogueur pour investiguer des problèmes présents dans les logiciels.
Description
Avec un débogueur, il est possible de trouver rapidement la cause d'un problème dans un logiciel. Le cas type d'utilisation est pour trouver les erreurs de segmentation. Si vous désirez trouver un problème de mémoire (par exemple, une fuite de mémoire), il est conseillé d'utiliser Valgrind.
Cas d'utilisation
Trouver la cause d'une erreur de segmentation directement avec le débogueur
Dans cette section, le programme suivant est utilisé :
#include <iostream>
#include <vector>
using namespace std;
int main(int argc, char**argv) {
vector<int> numbers;
int iterator = 1000;
while(iterator --) {
numbers.push_back(iterator);
}
cout << numbers[1000000] << endl;
return 0;
}
Ce programme génère une erreur de segmentation lorsqu'on l'exécute.
[name@server ~]$ g++ -g program.cpp -o program
[name@server ~]$ ./program
Segmentation fault (core dumped)
[name@server ~]$
On peut alors l'exécuter à l'intérieur du débogueur. Notez qu'on a compilé avec l'option -g pour permettre au débogueur de décoder les symboles et fournir davantage d'information sur la source du bogue. On exécute l'application à l'intérieur du débogueur comme suit :
[name@server ~]$ gdb ./program
(gdb) run
Starting program: /home/seb/program ./program
Program received signal SIGSEGV, Segmentation fault.
0x0000000000400c17 in main (argc=2, argv=0x7fffffffda88) at program.cpp:15
15 cout << numbers[1000000] << endl;
Missing separate debuginfos, use: debuginfo-install glibc-2.16-31.fc18.x86_64 libgcc-4.7.2-8.fc18.x86_64 libstdc++-4.7.2-8.fc18.x86_64
(gdb) bt
#0 0x0000000000400c17 in main (argc=2, argv=0x7fffffffda88) at program.cpp:15
Ici, l'erreur est causée par la ligne 15. Le code accède à l'indice 1000000, mais le tableau contient seulement 1000 éléments.
Trouver la cause d'une erreur de segmentation avec un fichier core
Dans cet exemple, on utilise le programme de la section précédente, mais sans utiliser le débogueur directement. Ceci est utile pour un bogue qui se produit longtemps après le début de l'exécution du programme.
Afin de trouver la cause de l'erreur de segmentation, il faut générer un fichier core. Pour ce faire, il faut activer la création de tels fichiers.
[name@server ~]$ ulimit -c unlimited
En exécutant à nouveau le même programme, un fichier core sera écrit.
[name@server ~]$ ./program
Segmentation fault (core dumped)
[name@server ~]$ file core.18158
core.18158: ELF 64-bit LSB core file x86-64, version 1 (SYSV), SVR4-style, from './program'
[name@server ~]$
En utilisant l'exécutable programme et le fichier core, il est possible de tracer l'exécution jusqu'à l'erreur.
[name@server ~]$ gdb -q ./program
Reading symbols from /home/seb/program...done.
(gdb) core-file core.18246
[New LWP 18246]
Core was generated by './program'.
Program terminated with signal 11, Segmentation fault.
#0 0x0000000000400c17 in main (argc=1, argv=0x7fff2315c848) at
program.cpp:15
15 cout << numbers[1000000] << endl;
Missing separate debuginfos, use: debuginfo-install
glibc-2.16-31.fc18.x86_64 libgcc-4.7.2-8.fc18.x86_64
libstdc++-4.7.2-8.fc18.x86_64
(gdb) bt
#0 0x0000000000400c17 in main (argc=1, argv=0x7fff2315c848) at
program.cpp:15
On obtient alors le même résultat qu'en ayant exécuté le code à l'intérieur du débogueur.
Attacher le débogueur à un processus existant
Il est possible de déboguer un processus existant, par exemple une tâche qui s'exécute sur un nœud de calcul. Pour ce faire, il faut d'abord trouver le numéro du processus.
[name@server ~]$ ps aux | grep firefox | grep -v grep
seb 12691 6.4 7.5 1539672 282656 ? Sl 08:53 6:48 /usr/lib64/firefox/firefox http://www.google.ca/
Ensuite, il est possible d'attacher le débogueur directement.
[name@server ~]$ gdb attach 12691
Après avoir fait cette commande, beaucoup d'information sera imprimée.
Plusieurs commandes de débogage sont disponibles. L'une des commandes utiles est backtrace, ou bt. Cette commande permet d'afficher la pile d'appels en cours.
(gdb) bt
#0 0x00000033646e99ad in poll () from /lib64/libc.so.6
#1 0x0000003db86849f3 in PollWrapper(_GPollFD*, unsigned int, int) () from /usr/lib64/firefox/xulrunner/libxul.so
#2 0x0000003366e47d24 in g_main_context_iterate.isra.24 () from /lib64/libglib-2.0.so.0
#3 0x0000003366e47e44 in g_main_context_iteration () from /lib64/libglib-2.0.so.0
#4 0x0000003db86849a2 in nsAppShell::ProcessNextNativeEvent(bool) () from /usr/lib64/firefox/xulrunner/libxul.so
#5 0x0000003db869a7d1 in nsBaseAppShell::DoProcessNextNativeEvent(bool, unsigned int) () from /usr/lib64/firefox/xulrunner/libxul.so
#6 0x0000003db869a8ea in nsBaseAppShell::OnProcessNextEvent(nsIThreadInternal*, bool, unsigned int) () from /usr/lib64/firefox/xulrunner/libxul.so
#7 0x0000003db89810c2 in nsThread::ProcessNextEvent(bool, bool*) () from /usr/lib64/firefox/xulrunner/libxul.so
#8 0x0000003db89563eb in NS_ProcessNextEvent(nsIThread*, bool) () from /usr/lib64/firefox/xulrunner/libxul.so
#9 0x0000003db873056f in mozilla::ipc::MessagePump::Run(base::MessagePump::Delegate*) () from /usr/lib64/firefox/xulrunner/libxul.so
#10 0x0000003db89a4ab7 in MessageLoop::Run() () from /usr/lib64/firefox/xulrunner/libxul.so
#11 0x0000003db869a1b3 in nsBaseAppShell::Run() () from /usr/lib64/firefox/xulrunner/libxul.so
#12 0x0000003db857d92d in nsAppStartup::Run() () from /usr/lib64/firefox/xulrunner/libxul.so
#13 0x0000003db7d18f4a in XREMain::XRE_mainRun() () from /usr/lib64/firefox/xulrunner/libxul.so
#14 0x0000003db7d1b007 in XREMain::XRE_main(int, char**, nsXREAppData const*) () from /usr/lib64/firefox/xulrunner/libxul.so
#15 0x0000003db7d1b259 in XRE_main () from /usr/lib64/firefox/xulrunner/libxul.so
#16 0x0000000000402c23 in do_main(int, char**, nsIFile*) ()
#17 0x0000000000402403 in main ()
(gdb) quit
A debugging session is active.
Inferior 1 [process 12691] will be detached.
Quit anyway? (y or n) y
Detaching from program: /usr/lib64/firefox/firefox, process 12691
Utilisation plus avancée
Dans les sections précédentes, nous avons utilisé les commandes run et backtrace. Plusieurs autres commandes sont disponibles pour déboguer en mode interactif, soit en contrôlant l'exécution du programme. Il est par exemple possible de fixer des points d'arrêt sur des fonctions ou des lignes de code ou encore lors d'une modification d'une variable. Lorsque l'exécution est interrompue, il est possible d'analyser l'état du programme en affichant la valeur de certaines variables. Le tableau ci-dessous contient une liste des principales commandes.
Commande | Raccourci | Argument | Description |
---|---|---|---|
run/kill | r/k | - | débute/arrête l'exécution du programme |
where / backtrace | bt | - | affiche la pile d'appel |
break | b | src.c:numero_de_ligne ou fonction | crée un point d'arrêt à la ligne de code ou à la fonction spécifiée |
watch | - | nom de variable | arrête l'exécution lorsque la variable est modifiée |
continue | c | - | continue l'exécution après un point d'arrêt |
step | s | - | exécute l'opération suivante |
p | nom de variable | affiche le contenu d'une variable | |
list | l | src.c:numéro | affiche la ligne de code spécifiée |
Afficher les structures de la STL
Par défaut, GDB n'affiche pas très bien le contenu des structures de la librairie standard du C++ (STL). Plusieurs solutions sont documentées ici. La solution la plus simple est probablement celle-ci, qui consiste à copier ce fichier dans votre répertoire d'accueil, sous le nom ~/.gdbinit.