Améliorez la qualité du code et évitez les résultats inattendus en apprenant à utiliser GNU Debugger pour révéler les bogues indésirables dans votre code.

Le débogage est une compétence indispensable pour les programmeurs et les chercheurs en sécurité. Avoir une bonne maîtrise du débogage vous permet de comprendre un exécutable à un niveau inférieur et de détecter les erreurs cachées.

Le débogueur GNU ou GDB est un outil de débogage intemporel sur lequel les programmeurs comptent depuis des années maintenant. Voici comment utiliser GDB sous Linux.

Préparation d'exemples de programmes

Pour explorer les fonctionnalités de GDB, vous aurez besoin d'un exécutable avec lequel expérimenter. Pour la démonstration, vous exécuterez GDB sur un programme de vérification de clé une fois avec le code source et les symboles de débogage disponibles, une fois sans code source, et sur un simple programme multithread qui imprime des messages à l'écran, à la fois écrits en C et compilés avec GCC (GNU C Compilateur).

instagram viewer

Tu peux utiliser n'importe quel autre compilateur C mais assurez-vous de ne pas supprimer le binaire.

Vous exécuterez probablement GDB sur vos propres programmes. Assurez-vous donc de les compiler avec le -g flag avec gcc pour activer les symboles de débogage.

Sans les symboles de débogage présents et avec un binaire fortement dépouillé, vous devrez déboguer le désassemblage du programme. Cela nécessitera que vous ayez une solide maîtrise du langage assembleur et comment fonctionne l'allocation de mémoire sous Linux pour comprendre les données de la pile et des registres.

Exécuter un programme dans GDB

Vous exécutez un programme dans GDB de plusieurs manières. Soit vous tapez gdb , et une fois chargé, tapez courir. Ou démarrez gdb puis utilisez le déposer commande, chargez le binaire dans gdb, puis exécutez-le avec le courir commande.

Si votre programme nécessite des arguments de ligne de commande pour fonctionner correctement, assurez-vous d'ajouter les arguments après le nom du programme. Voici la syntaxe pour charger le programme sur GDB et l'exécuter avec des arguments :

gdb 
run

Ou:

gdb
file
run

Définition de points d'arrêt avec GDB

Les points d'arrêt dans le débogage sont des arrêts brusques définis manuellement dans le code qui arrêtent le flux d'exécution lorsque le programme atteint un point d'arrêt. La définition de points d'arrêt vous permet de parcourir le code et d'inspecter comment chaque étape de l'exécution affecte les données et les variables.

Dans GDB, lorsque vous déboguez un programme avec des symboles de débogage, vous pouvez soit définir un point d'arrêt par le nom de la fonction, soit définir un point d'arrêt basé sur le numéro de ligne. Voici la syntaxe :

break main
break 47

Pour afficher tous les points d'arrêt de la session de débogage en cours, tapez :

info breakpoints

Pour supprimer un point d'arrêt particulier ou plusieurs points d'arrêt, tapez :

delete 2
delete 3-5

GDB vous permet également de définir des points d'arrêt conditionnels, ce qui signifie que le programme ne s'arrêtera que si une condition particulière est remplie lors de l'exécution. Il peut s'agir du changement de valeur d'une variable ou d'un appel de fonction infructueux ou de tout ce que vous voulez. Voici la syntaxe pour définir des points d'arrêt conditionnels :

break  if n == 2

Si vous souhaitez continuer l'exécution du programme après avoir atteint un point d'arrêt, tapez le continuer commande:

continue

Parcourir le code

Parcourir le code est crucial pour comprendre comment le programme gère les données. En parcourant différentes fonctions de votre programme et en examinant l'état des données, vous pouvez mieux comprendre comment le programme implémente la logique que vous avez écrite dans le code.

Il vous aide également à détecter la racine des plantages et à étudier le comportement du programme avec une précision chirurgicale, car vous pouvez parcourir chaque ligne de code à votre guise. Vous pouvez parcourir le code de trois manières principales dans GDB :

  1. étape: Cette commande indique à GDB de passer à la ligne suivante du fichier source. Cela vous permet essentiellement de parcourir la longueur du code source ligne par ligne.
  2. suivant: Cette commande exécute la ligne suivante du code source à l'intérieur de la fonction actuelle, puis s'arrête. suivant traite une fonction comme une seule ligne, donc si vous utilisez next avant un appel de fonction, il la traitera comme une seule ligne et la franchira, contrairement au étape commande.
  3. finition: La commande finish exécute toutes les lignes restantes à l'intérieur de la fonction actuelle, puis s'arrête.

Examen des variables

Au fur et à mesure que vous parcourez le code, vous souhaiterez examiner la valeur des variables pour voir comment la logique du programme les modifie. Voici la syntaxe pour afficher la valeur des variables dans GDB :

print 

Si vous souhaitez imprimer les modifications de la valeur d'une variable à chaque fois qu'elle est mise à jour, vous devez utiliser la commande display. Ceci est particulièrement utile lorsque vous souhaitez suivre et imprimer la valeur d'une variable dans une boucle :

display 

Définition des points de surveillance

Les points de surveillance et les points d'arrêt conditionnels sont étroitement liés car ils répondent tous deux aux modifications apportées à un programme. Les points de surveillance sont utilisés pour suivre les modifications des données dans le code. Par exemple, vous souhaiterez peut-être que le programme s'arrête chaque fois que la valeur d'une variable change. Voici comment procéder avec GDB :

watch 

Débogage spécifique au thread avec GDB

GDB vous permet d'effectuer un débogage spécifique au thread lorsque vous travaillez avec des programmes multithread. Pour la démonstration, nous travaillerons avec un simple programme C qui utilise quatre threads pour imprimer des messages avec chaque thread.

Pour afficher les threads actuellement générés dans votre programme, utilisez le Info commande:

info threads

Pour travailler avec un fil de discussion spécifique, vous pouvez le sélectionner dans la liste en utilisant son numéro d'index. Par exemple:

thread 2

Après avoir sélectionné le thread, vous pouvez parcourir son flux d'exécution à l'aide du étape, suivant, et finition commandes comme démontré ci-dessus.

Débogage à distance avec GDB

Vous pouvez également déboguer à distance des programmes situés sur un autre système. Pour ce faire, vous devez configurer gdbserver sur la machine cible. Vous pouvez facilement l'installer en utilisant le gestionnaire de paquets par défaut de votre distribution ou autres gestionnaires de paquets que vous avez installés sur votre système.

Par exemple, pour installer gdbserver sur vos systèmes Ubuntu ou Debian, utilisez APT :

sudo apt install gdbserver

Une fois installé, déplacez-vous dans le dossier du binaire et exécutez cette commande pour démarrer gdbserver :

gdbserver :

gdbserver devrait renvoyer la sortie indiquant qu'il est actif et écoute sur le port que vous avez défini. Maintenant sur la machine client, démarrez GDB puis connectez-vous au serveur distant à l'aide du cible commande:

target remote :

Écriture de scripts GDB pour automatiser le débogage

GDB permet aux programmeurs d'écrire des scripts GDB qui exécuteront automatiquement les commandes GDB. Cela aide énormément lorsque vous essayez de déboguer plusieurs fois la même partie d’un code. Au lieu d'avoir à définir le point d'arrêt, à parcourir le code et à imprimer les valeurs des variables à chaque fois que vous chargez le binaire, vous pouvez utiliser un script GDB pour automatiser l'ensemble du processus.

Voici un exemple :

set logging enabled on
set logging file sample.out
break main
command 1
backtrace
print N
continue
end
quit

Dans le script ci-dessus, vous demandez à GDB d'activer la journalisation et d'enregistrer le journal dans un fichier appelé échantillon.out, puis définissez un point d'arrêt au principal fonction.

Pour le point d'arrêt numéro 1, dans ce cas, le point d'arrêt de la fonction main, exécutez les commandes suivantes: trace, imprimer, continuer. Fondamentalement, GDB exécutera d'abord une trace, puis imprimera la valeur de la variable "N", poursuivra l'exécution et enfin quittera.

Pour exécuter ce script, utilisez :

gdb -x