- gdbserver agit comme un agent distant de GDB pour contrôler des processus sur une autre machine via TCP ou série.
- Pour déboguer à distance, il est essentiel de compiler avec SymbolesUtilisez la version appropriée de gdb et configurez correctement les chemins d'accès aux symboles et aux polices.
- gdbserver propose un mode mono-processus et un mode multi-processus, et s'intègre également à WinDbg et QEMU pour le débogage du noyau.
- Des options telles que --debug, sysroot et les limites de taille des valeurs aident à diagnostiquer les problèmes et à stabiliser les sessions.
Si vous programmez en C ou C++ dans Linux et vous n'avez jamais touché à gdbserverVous passez à côté d'un outil extrêmement utile pour le débogage à distance, que ce soit sur un serveur, un système embarqué, ou même au sein d'une machine virtuelle ou de WSL. Loin d'être un outil « magique » ou réservé aux experts, gdbserver est simplement un petit programme qui communique avec gdb et contrôle l'exécution du processus cible.
L'idée principale est très simple.: sur la machine où s'exécute le binaire que vous souhaitez déboguer (le l'objectif) vous lancez gdbserver ; sur votre ordinateur professionnel (le hôteVous lancez gdb ou WinDbg avec prise en charge du protocole gdb. Ces deux outils se connectent via TCP ou un port série, et vous pouvez ensuite définir des points d'arrêt, examiner les variables, visualiser la pile d'exécution ou suivre l'exécution pas à pas comme si le programme s'exécutait sur votre propre machine.
Qu'est-ce que gdbserver et dans quels cas est-il judicieux de l'utiliser ?

gdbserver est un « agent » de débogage à distance pour GNU gdbSa fonction est très spécifique : elle s'exécute sur la machine où le programme à analyser est exécuté, contrôle ce processus (ou ces processus) et communique avec un client gdb situé sur une autre machine (ou sur la même) via une connexion à distance.
Au quotidien, gdbserver est utilisé dans deux scénarios typiques :Logiciels de débogage fonctionnant dans des environnements embarqués (routeurs, cartes avec Linux allégé, périphériques) IoTetc.) et déboguer des processus sur des machines Linux distantes, où il n'est pas pratique ou tout simplement impossible d'avoir un gdb « complet » avec toutes les bibliothèques et tous les symboles.
Sur le plan pratique, gdbserver gère des tâches telles que Lire et écrire dans les registres et la mémoire du processus, contrôler l'exécution (continuer, mettre en pause, exécuter pas à pas), gérer les points d'arrêt et envoyer toutes ces données à gdb via le protocole distant GDB. Cette approche est très similaire à celle d'outils comme OpenOCD, qui servent d'interface entre gdb et un système de fichiers. matériel externe, à la différence que gdbserver s'exécute sur le même système que le binaire.
Si vous venez d'environnements Windows Il est également intéressant de savoir Les débogueurs comme WinDbg peuvent communiquer avec un serveur gdb sous Linux, ce qui permet de déboguer les processus utilisateur sous Linux depuis WinDbg en utilisant la prise en charge du débogage à distance via le protocole gdb que Microsoft a intégré dans les versions récentes.
Configuration requise de base pour le débogage avec gdb et gdbserver

Avant de commencer le débogage à distance, vous devez comprendre la relation hôte/cible.. Le l'objectif Il s'agit de la machine sur laquelle s'exécute le programme à déboguer et sur laquelle gdbserver sera exécuté ; hôte C'est sur cette machine que vous exécuterez gdb (ou WinDbg) et où se trouveront le code source et, de préférence, les symboles de débogage.
Le point de départ essentiel est de compiler le binaire avec des symbolesDans GCC ou g++, cela se fait avec l'option `--flag`. -get il est généralement conseillé de désactiver également les optimisations (par exemple avec -O0Cela permet au débogueur d'afficher plus précisément les variables, les macros et la structure du code. Pour certaines macros, vous pouvez utiliser des niveaux de débogage plus élevés, tels que : -g3.
Côté hôte, vous aurez besoin d'une version compatible de gdb avec l'architecture cible. Pour déboguer un système embarqué MIPS, ARM ou autre architecture, vous devez utiliser gdb de la chaîne d'outils de compilation croisée correspondante (par exemple). arm-none-eabi-gdb o gdb-multiarchet, si nécessaire, configurer l'architecture et l'endianness avec commandes como set arch y set endian.
En ce qui concerne la connexion, gdbserver prend en charge deux types principauxUne liaison série (très courante dans les systèmes embarqués, via UART) et TCP/IP, ce dernier étant particulièrement pratique lorsque la cible se trouve sur le même réseau ou s'il s'agit d'une machine Linux accessible via le réseau. Dans les deux cas, la commande est utilisée depuis gdb. target remote se connecter au point de terminaison exposé par gdbserver.
Méthodes de démarrage de gdbserver : mode mono-processus et mode multi-processus

gdbserver peut fonctionner de deux manières principales Lorsque nous parlons de débogage en mode utilisateur : directement associé à un seul processus ou en tant que « serveur de processus » qui permet de lister et de se connecter à différents processus système.
En mode monoprocessus Vous lancez gdbserver en spécifiant l'hôte, le port et le programme à exécuter. Sur un ordinateur de bureau Linux, par exemple, vous pourriez procéder comme suit :
Commande: gdbserver localhost:3333 foo
Cette commande permet à gdbserver de démarrer le binaire. foo et il reste à l'écoute sur le port 3333Tant qu'une instance gdb distante ne se connecte pas, le programme reste arrêté ; lorsque gdb se connecte avec target remote localhost:3333, le processus commence alors à être contrôlé par le débroyeur.
En mode multiprocessus (serveur de processus), cette option est utilisée. --multiDans ce cas, gdbserver ne lance aucun programme directement, mais écoute simplement les connexions entrantes et permet au client (gdb ou WinDbg) de gérer le processus à créer ou auquel se connecter :
Commande: gdbserver --multi localhost:1234
Ce mode multiple est particulièrement intéressant lorsqu'on travaille avec WinDbg sous Linux.Parce que WinDbg permet de lister les processus sur le système distant, d'afficher leur PID, leur utilisateur et leur ligne de commande, et de s'attacher au processus qui vous intéresse, de la même manière qu'avec un serveur de processus. dbgsrv.exe sous Windows.
Débogage à distance avec gdbserver et gdb étape par étape
Prenons un exemple très concret pour illustrer cela.Déboguer une application simple sur la même machine (hôte et cible identiques) en utilisant gdbserver pour simuler le scénario distant.
Vous commencez par écrire et compiler un petit programme.Par exemple, une boucle simple qui affiche un compteur :
Commande: gcc -g foo.c -o foo
L'élément clé ici, c'est le drapeau. -gCela ajoute les informations de débogage nécessaires au binaire afin que gdb puisse afficher les lignes de code, les noms de variables, les types, etc. Dans un environnement de compilation croisée « réel », vous effectueriez cette compilation avec la chaîne d'outils croisée, puis vous copieriez le binaire et ses dépendances vers la cible.
L'étape suivante consiste à démarrer gdbserver sur la cibleSi l'hôte et la cible sont la même machine, alors :
Commande: gdbserver localhost:3333 foo
Vous verrez un message similaire à « Processus foo créé ; pid = XXXX ; Écoute sur le port 3333 ». Ceci indique que gdbserver a créé le processus et attend la connexion de gdb. Si vous utilisez un système nécessitant davantage de privilèges (par exemple, pour vous connecter aux processus système), vous devrez peut-être exécuter la commande avec… sudoMais il est toujours sage de faire preuve de prudence lorsqu'on accorde une autorisation. racine au désulfuriseur.
Sur l'hôte, vous lancez gdb en spécifiant l'exécutable local (le même que celui qui s'exécute sur la cible, ou une copie identique avec les symboles) :
Commande: gdb foo
Une fois à l'intérieur de gdb, vous établissez la connexion distante avec:
Commande: target remote localhost:3333
À ce stade, gdb charge les symboles à partir du binaire local.Il se synchronise avec gdbserver et prend le contrôle du processus exécuté par gdbserver. Ensuite, le flux est habituel : des commandes comme break définir des points de rupture, continue, step, next, print pour examiner les variables, backtrace pour voir la batterie, etc.
Connexion aux processus en cours d'exécution avec gdbserver
Il n'est pas toujours souhaitable de lancer le programme à partir de zéro.Souvent, vous souhaitez rejoindre un processus déjà en cours (par exemple, un httpd d'un toupieun démon système ou un service de production).
Le schéma typique consiste à utiliser l'option --attach depuis gdbserverIl faut indiquer le port d'écoute et l'identifiant du processus cible (PID). Par exemple, sur un routeur où vous avez copié un serveur gdb compilé pour son architecture, vous pouvez procéder comme suit :
Commande: gdbserver localhost:3333 --attach <pid_de_httpd>
Côté hôte, vous utiliserez une version de gdb compatible avec l'architecture du routeur., par exemple gdb-multiarchconfigurer au préalable l'architecture et l'endianness :
Commande: set arch mips
set endian big
Ensuite, vous spécifiez le fichier local qui contient les symboles. du binaire distant (par exemple file httpdet, si nécessaire, vous indiquez à gdb où le binaire est effectivement exécuté sur la cible avec set remote exec-file /usr/bin/httpdEnfin, comme précédemment, vous vous connectez avec :
Commande: target remote 192.168.0.1:3333
Une fois attachéVous pouvez définir des points d'arrêt sur des fonctions spécifiques (par exemple, break checkFirmware), poursuivre l'exécution et laisser le flux normal du programme (téléchargement du firmware depuis l'interface web, par exemple) déclencher le point d'arrêt.
Utilisation de gdbserver avec WinDbg sous Linux
Ces dernières années, Microsoft a ajouté la prise en charge du débogage des processus Linux dans WinDbg. Utilisation de gdbserver comme backend. Cette fonctionnalité est conçue pour les scénarios où vous travaillez sous Windows mais où le code s'exécute sous Linux (y compris WSL).
Déboguer un processus Linux spécifique avec WinDbg en utilisant gdbserverLe processus se déroulerait comme suit : vous commencez par localiser le processus cible sur la machine Linux à l’aide d’une commande du type : ps -A (par exemple un python3 (qui est en cours d'exécution), puis vous lancez gdbserver sur la cible :
Commande: gdbserver localhost:1234 python3
Si l'environnement l'exige, vous pourriez avoir besoin d'utiliser sudo gdbserver ...En respectant les mêmes précautions de sécurité qu'auparavant. Une fois que gdbserver indique qu'il « Écoute sur le port 1234 », dans WinDbg, allez dans « Fichier / Se connecter au débogueur distant » et spécifiez une chaîne de connexion du type suivant :
Commande: gdb:server=localhost,port=1234
WinDbg utilise un petit « pilote » de protocole gdb pour communiquer avec gdbserver. et, une fois la connexion établie, elle reste bloquée au point de Botte du processus. À partir de là, vous pouvez utiliser ses fenêtres de pile, ses modules, sa mémoire, ses points d'arrêt, ainsi que des commandes comme k pour voir la batterie ou lm pour lister les modules (en gardant à l'esprit que certaines commandes attendent le format PE et non ELF, elles peuvent donc afficher des données étranges dans certains cas).
serveur de processus gdbserver et WinDbg
Outre le cas d'un processus unique, WinDbg peut se connecter à un serveur gdbserver faisant office de serveur de processus. pour fonctionner de manière plus similaire à son fonctionnement avec les processus Windows distants. Dans ce mode, gdbserver est lancé avec --multi et sans processus associé :
Commande: sudo gdbserver --multi localhost:1234
Dans WinDbg, choisissez « Fichier / Se connecter au serveur de processus ». et vous réutilisez la chaîne de connexion gdb:server=localhost,port=1234Lorsque la connexion est active, vous pouvez lister les processus Linux disponibles et vous connecter à celui de votre choix, ou même lancer un nouveau processus.
Un détail subtil doit être pris en compte.WinDbg fait la distinction entre « serveur de processus » et « cible unique » selon que gdbserver est déjà attaché à un processus ou non lors de la connexion. Si vous avez laissé gdbserver attaché à un processus, fermé WinDbg, puis tenté de vous reconnecter, il se peut qu'il ne soit pas détecté comme serveur de processus et vous devrez peut-être le redémarrer.
Pour mettre fin à une session de serveur de traitementEn général, il suffit d'appuyer sur CTRL+D dans la console où gdbserver est exécuté et d'arrêter le débogage depuis WinDbg. Dans certains cas extrêmes, en cas de problèmes de synchronisation, il peut être nécessaire de fermer complètement le débogueur et de redémarrer gdbserver.
Gestion des symboles et du code source lors du débogage à distance
L'une des clés pour faciliter le débogage à distance est de bien résoudre la partie concernant les symboles et les polices.Sans symboles, naviguer dans la pile ou définir des points d'arrêt sur des fonctions spécifiques devient un véritable supplice.
Dans les scénarios classiques gdb + gdbserver, l'idéal est de conserver une copie de l'exécutable avec les symboles sur l'hôte. (non dépouillé) et l'arborescence source. gdb n'exige pas que le binaire distant contienne les symboles ; il suffit que le fichier local que vous chargez avec file faire correspondre l'exécutable distant au niveau du décalage.
Dans le monde du débogage WinDbg et Linux, des services comme DebugInfoD ont également fait leur apparition.qui exposent des symboles et des polices via HTTP. WinDbg peut utiliser des chemins spéciaux du type DebugInfoD*https://debuginfod.elfutils.org tous les deux .sympath ou pendant .srcpath pour télécharger à la demande les symboles DWARF et le code source des binaires ELF Linux.
Dans un exemple précis avec WSL, où le code utilisateur se trouve sous C:\Users\Bob\Vous pourriez le dire à WinDbg :
Commande: .sympath C:\Users\Bob\
.srcpath C:\Users\Bob\
Et si vous souhaitez également utiliser DebugInfoD pour les binaires système:
Commande: .sympath+ DebugInfoD*https://debuginfod.elfutils.org
.srcpath+ DebugInfoD*https://debuginfod.elfutils.org
Avec cette configuration, lorsque vous inspectez la pile ou entrez dans les fonctions de la libc,WinDbg peut tenter de télécharger les symboles DWARF correspondants et, si le serveur expose également le code, afficher le code source de manière très détaillée, bien que la chaîne d'outils Windows ne gère pas en interne les formats ELF et DWARF aussi « nativement » que les formats PE et PDB.
Exemple pratique : débogage d’un programme C++ avec gdbserver et WinDbg
À titre d'exemple, citons une petite application C++ qui affiche un message de bienvenue à l'écran., compilé sous WSL avec des symboles de débogage. Imaginez un programme qui réserve un std::array<wchar_t, 50> et y copie un message plus long, ce qui provoque la troncature du texte et l'apparition de caractères. ???? à la fin.
Après avoir compilé avec quelque chose comme:
Commande: g++ DisplayGreeting.cpp -g -o DisplayGreeting
Vous lancez gdbserver sur ce binaire.:
Commande: gdbserver localhost:1234 DisplayGreeting
Dans WinDbg, vous vous connectez avec la chaîne gdb:server=localhost,port=1234 Et, une fois la session établie et les chemins d'accès aux symboles et aux polices configurés, vous définissez un point d'arrêt dans DisplayGreeting!main, vous pouvez utiliser dx greeting pour inspecter le tableau local et voir sa taille (50 positions), et vérifier visuellement dans l'onglet mémoire ou dans la vue des variables comment le message de salutation est coupé.
L'intérêt de cet exemple réside dans le fait qu'il démontre que, même sans prise en charge complète de tous les formats ELF/DWARF dans WinDbgVous pouvez parcourir les piles d'appels, inspecter les types, définir des points d'arrêt par nom de fonction et naviguer assez facilement dans le code C++ en utilisant gdbserver comme backend distant.
Débogage du noyau Linux avec qemu et gdb
gdbserver n'est pas seulement utilisé en mode utilisateur ; il existe également des scénarios très puissants en mode noyau.En particulier lorsqu'on combine QEMU avec le support du débogage. Bien que le rôle de « gdbserver » soit ici assuré par une option native de QEMU, l'approche reste identique : d'un côté, le système à déboguer est exécuté et un port gdb est ouvert ; de l'autre côté, gdb ou un débogueur communique avec le protocole distant.
Pour déboguer le noyau, vous devez le compiler avec des options de débogage spécifiques.: activer la génération d'informations de débogage (CONFIG_DEBUG_INFO), les scripts du noyau GDB (CONFIG_GDB_SCRIPTS) et le mode de débogage propre au noyau (CONFIG_DEBUG_KERNELIl est également important de désactiver les options qui suppriment les symboles lors de la liaison, telles que « Supprimer les symboles générés par l'assembleur lors de la liaison ».
Après la compilation, vous obtiendrez un fichier binaire vmlinux « non dépouillé »C'est celui que vous utiliserez avec gdb. Vous aurez également besoin d'un initramfs de base, que vous pouvez générer avec une commande comme :
Commande: mkinitramfs -o ramdisk.img
Ensuite, vous lancez QEMU avec les paramètres de débogageUn exemple typique comprend l'option -gdb tcp::1234 pour ouvrir un point de terminaison distant compatible avec gdb, et -S afin que la machine virtuelle démarre en pause dès le début. Vous spécifiez également le noyau avec -kernel vmlinux, l' -initrd ramdisk.img, le souvenir avec -m 512 et vous redirigez généralement la console vers ttyS0 pour tout gérer depuis terminal.
Avec le QEMU retenu en attente de gdbDepuis la machine hôte, vous lancez gdb en le faisant pointer vers vmlinux et vous vous connectez avec target remote localhost:1234À partir de là, vous pouvez définir des points d'arrêt précoces, par exemple un hb start_kernelet contrôler l'exécution avec des commandes telles que c (continuer) et CTRL+C pour mettre en pause à nouveau.
Évolutions et nuances récentes de gdb et gdbserver
Dans les distributions modernes comme Red Hat Enterprise Linux 8, il existe un certain nombre de changements dans gdb et gdbserver qu'il convient de garder à l'esprit.surtout si vous utilisez des versions précédentes ou si vous avez des scripts qui analysent la sortie du débogueur.
D'une part, gdbserver lance désormais les processus « inférieurs » à l'aide d'un shell.Tout comme gdb, cette fonctionnalité permet l'expansion et la substitution de variables en ligne de commande. Si vous devez désactiver ce comportement, des paramètres spécifiques sont documentés dans RHEL 8 pour revenir au mode précédent.
Plusieurs éléments ont également été supprimés ou modifiés.: prise en charge du débogage pour les programmes Java compilés avec gcj, le mode de compatibilité HP-UX XDB, des commandes telles que set remotebaud (remplacé par set serial baud) ou la compatibilité avec un certain format plus ancien de stabsDe plus, la numérotation des threads n'est plus globale, mais par thread « inférieur », et apparaît comme suit : inferior_num.thread_num, avec de nouvelles variables de commodité telles que $_gthread faire référence à l'identifiant global.
Une autre nouveauté importante est le réglage max-value-sizeCela limite la quantité de mémoire que gdb peut allouer pour afficher le contenu d'une valeur. La valeur par défaut est de 64 Kio ; par conséquent, toute tentative d'affichage de tableaux ou de structures volumineux peut entraîner un avertissement « valeur trop grande » au lieu d'afficher toute la mémoire disponible.
La façon dont gdb gère le sysrootLa valeur par défaut est maintenant target:Cela signifie que pour les processus distants, il tentera d'abord de trouver les bibliothèques et les symboles sur le système cible. Si vous souhaitez qu'il privilégie les symboles locaux, vous devez exécuter la commande suivante : set sysroot avec l'itinéraire qui vous intéresse avant de faire target remote.
Concernant l'historique des commandes, la variable d'environnement actuellement utilisée est GDBHISTSIZE au lieu de HISTSIZECela vous permet d'ajuster précisément la durée de conservation des commandes saisies lors des sessions de débogage, sans interférer avec le comportement des autres applications utilisant la bibliothèque de lecture de lignes.
Conseils et dépannage pour l'utilisation de gdbserver
Pour un flux de travail confortable, certains modèles ont tendance à très bien fonctionner. Lors du développement pour systèmes embarqués ou serveurs distants, la première étape consiste à automatiser autant que possible la compilation des symboles et le déploiement du binaire sur la cible. Ainsi, vous savez toujours quelle version de l'exécutable est en cours d'exécution et vous disposez d'une copie des symboles facilement accessible sur l'hôte.
Dans les environnements comportant de nombreux cœurs sujets aux plantages, il est judicieux d'apprendre à utiliser gdb en mode batch., avec des drapeaux comme --batch, --ex y -x pour lancer automatiquement des commandes sur une liste de cœurs et traiter leurs traces d'exécution à partir de scripts (par exemple dans PythonCela vous permet de filtrer rapidement les problèmes récurrents, de regrouper les échecs par trace de pile, etc.
En cas de problème avec la connexion à distance, l'option --debug gdbserver est votre meilleur amiSi vous démarrez, par exemple, un serveur de processus avec :
Commande: gdbserver --debug --multi localhost:1234
La console gdbserver affichera des traces détaillées de ce qui se passe. Au niveau du protocole distant, cela inclut les paquets entrants, les erreurs de formatage, les problèmes de déconnexion, etc. Ceci est très utile lorsque votre serveur gdb se déconnecte soudainement, qu'un processus plante dès qu'un point d'arrêt est défini, ou que votre interface graphique de débogage envoie quelque chose que gdbserver ne comprend pas.
Dans des contextes tels qu'un routeur TP-Link où vous attachez gdbserver à un processus critique comme httpdIl arrive fréquemment que certains points d'arrêt génèrent des conditions de concurrence ou que des mécanismes de surveillance interrompent le processus lorsqu'il reste bloqué trop longtemps dans le débogueur. Dans ce cas, il peut être nécessaire d'ajuster les signaux bloqués, les threads contrôlés et, le cas échéant, de modifier la configuration système (délai d'expiration, mécanismes de surveillance matériels) afin de prolonger les sessions de débogage.
Bien utiliser gdbserver implique de combiner plusieurs élémentsCompilez avec les symboles appropriés, choisissez la version de gdb adaptée à l'architecture, configurez les chemins des symboles et des sources, comprenez les deux principaux modes de gdbserver (monoprocessus et multiprocessus) et n'hésitez pas à utiliser le mode multiprocessus. --debug lorsque la connexion ne se comporte pas comme prévu. Grâce à ces bases, le débogage d'applications exécutées sur un système Linux distant, un routeur ou une machine virtuelle avec un noyau personnalisé depuis votre PC devient une procédure courante et, surtout, extrêmement utile.
Écrivain passionné par le monde des octets et de la technologie en général. J'aime partager mes connaissances à travers l'écriture, et c'est ce que je vais faire dans ce blog, vous montrer toutes les choses les plus intéressantes sur les gadgets, les logiciels, le matériel, les tendances technologiques et plus encore. Mon objectif est de vous aider à naviguer dans le monde numérique de manière simple et divertissante.