Catégorie : Programmation     Tags :      

    Retrouvez cet article dans : Linux Magazine 88

    Le précédent article de la série « Programmation noyau sous Linux » a introduit les techniques de développement des pilotes. Nous allons ici nous consacrer à leur mise au point grâce à GDB et KGDB. Après un rapide tour d’horizon des solutions disponibles, nous détaillerons le composant libre KGDB permettant la mise au point du noyau Linux et des modules dynamiques développés par l’utilisateur. La description de la mise en œuvre de KGDB s’inspire d’un document draft interne initialement écrit par Emmanuel Huck.

    Mise au point des programmes sous Linux

    La chaîne de développement GNU fournit l’outil de débogage GDB (GNU DeBugger). Ce dernier peut être utilisé directement avec son interface en mode texte mais il est souvent intégré dans des outils de développement plus graphiques et « conviviaux » tels Kdevelop ou Eclipse. Cependant, c’est avant tout une question de choix et d’habitudes de l’utilisateur. Dans le présent article, nous ferons référence à la syntaxe de GDB dans son environnement initial en mode texte.
    Par défaut, le débogueur GDB est disponible uniquement dans l’espace utilisateur. Cependant, il est fréquent que les développeurs de logiciels embarqués aient à développer et donc mettre au point des pilotes de périphériques lesquels sont exécutés dans l’espace du noyau. De même, il peut arriver qu’il soit nécessaire de modifier le code source du noyau Linux. Dans le numéro HS24, nous avions cité rapidement la possibilité d’utiliser GDB pour de la mise au point à distance (ou remote debugging) en utilisant un agent de mise au point installé sur le système cible (soit gdbserver dans ce cas). Grâce à cette technique, il est possible de mettre au point un programme exécuté sur une cible distante d’architecture donnée (exemple : ARM Linux), et ce, depuis un poste de développement utilisant une architecture totalement différente (exemple : PC x86 sous Linux ou Windows/CygWin). Le lien entre les deux systèmes s’effectue au travers d’une liaison Ethernet ou bien à défaut d’un lien série RS-232. Coté cible, on pourra exécuter l’application de la manière suivante :

     $ gdbserver 192.168.1.1:4444 mon_application

    L’adresse 192.168.1.1 correspond au système de développement, la valeur 4444 à un port TCP disponible pour le dialogue réseau entre gdb et gdbserver. Coté poste de développement, on utilisera la syntaxe suivante :

    $ arm-linux-gdb mon_application
    (gdb) target remote 192.168.3.2:4444
    (gdb) b main
    (gdb) continue

    L’adresse IP 192.168.3.2 correspond  à celle de la cible. Notez que dans notre cas, la cible utilise un processeur de type ARM. Le programme gdb à utiliser sur le poste de développement (PC x86) n’est pas la version native x86, mais un débogueur croisé (cross debugger) capable de traiter du code ARM. Ce débogueur arm-linux-gdb est intégré à la chaîne de compilation croisée.

    Tour d’horizon des solutions disponibles

    Divers outils et techniques sont disponibles pour la mise au point des programmes dans l’espace noyau de Linux. En voici une liste non exhaustive. Il est important de noter que certains outils sont encore expérimentaux.

    • La traditionnelle méthode du printk (l’équivalent du printf dans l’espace du  noyau). Cette méthode a l’avantage d’être simple (voire simpliste) et peut suffire dans le cas de problèmes relativement simples. Elle a l’inconvénient d’être intrusive, puisque le code source est modifié par l’ajout des lignes contenant les appels à printk. Les messages sont visibles en utilisant la commande dmesg ou bien en consultant les traces du système suivant la configuration du démon syslogd.
    • La commande strace ne permet pas de mettre au point dans l’espace du noyau, mais permet d’obtenir la liste des appels système (donc des requêtes au noyau) effectuées par un programme utilisateur. L’outil est simple, mais se révèle être d’une redoutable efficacité. Notez que la commande ltrace permet d’obtenir la liste des appels aux bibliothèques.
    • L’outil LTT permet également de tracer les appels système, et ce, de manière beaucoup plus avancée (allocation mémoire, utilisation du processeur, synchronisation, etc.). Une version pour le noyau 2.6 existe sous le nom LTTng.
    • L’outil Ksymoops permet d’effectuer une analyse de l’erreur après un « crash » du noyau (analyse post-mortem), en analysant le contenu des messages oops du noyau. Dans le même ordre d’idées, l’outil LKCD (pour Linux Kernel Crash Dump) permet de sauver l’état du noyau en cas de crash, puis de l’exploiter ultérieurement grâce à la commande lcrash.
    • L’outil Netdump permet de transmettre l’image mémoire à un serveur via Ethernet et de l’exploiter ultérieurement avec GDB.
    • Dans le cas de mise au point très bas niveau, on peut envisager le débogage au travers d’un port JTAG à condition que ce dernier soit disponible sur la carte. Il est nécessaire de disposer d’une sonde JTAG et du logiciel associé qui est souvent propriétaire et parfois coûteux.
    • La simulation peut être une solution intéressante pour la mise au point. On peut exécuter le noyau en espace utilisateur grâce au patch UML (pour User Mode Linux) qui permet de ce fait d’utiliser GDB directement. Cependant, l’exécution est alors beaucoup plus lente. De plus, il ne s’agit que d’une simulation et non des conditions réelles.
    • Le patch KDB est diffusé par SGI. Il permet d’interrompre l’exécution du noyau ou bien de poser des points d’arrêt, mais il est uniquement utilisable au niveau assembleur (et non pas au niveau du code source).
    • Kprobes est un système d’instrumentation dynamique du noyau Linux. Il est intégré au noyau 2.6 sous forme de module depuis la version 2.6.9. Kprobes permet d’ajouter des fonctions de traitement (pre-handler, post-handler, fault-handler, etc.) dans un module du noyau afin de récupérer des traces d’exécution.
    • SystemTap est un langage de script basé sur Kprobes. La commande stap génère des modules Kprobes. Cependant,SystemTap est encore expérimental et n’est pas réellement utilisable dans un environnement industriel.
    • Le patch KGDB utilise le même principe que l’agent gdbserver décrit précédemment. Grâce à KGDB, il est possible de mettre au point du code source exécuté dans l’espace noyau d’un système donné, et ce, au travers d’un lien Ethernet ou série RS-232. Ce principe nécessite deux machines, mais il est plus efficace que les autres solutions disponibles. Logiquement, il paraît en effet assez difficile de mettre au point le noyau Linux (ou un pilote de périphérique) sur un système tout en utilisant les outils de mise au point sur ce même système ! La solution KGDB nous paraissant être la plus fiable, nous l’étudierons en détail dans la suite de cet article.

    Mise en œuvre de KGDB

    Le composant KGDB est maintenu par la société Linsyssoft (http://www.linsyssoft.com). La version libre de KGDB est disponible en téléchargement, mais l’éditeur diffuse également une version commerciale. Notez également que KGDB est intégré à des outils commerciaux tels le Workbench édité par Wind River. Au moment de la rédaction de cet article, la version disponible est la 2.4, adaptée au noyau 2.6.15.5. D’autres versions plus anciennes sont cependant disponibles sur la page de téléchargement de Linsyssoft. KGDB est actuellement disponible pour les architectures x86, ia64, x86_64, arm, powerpc et sh (Super Hitachi). Dans le cas présent, nous utiliserons un lien série RS-232 entre la station de développement et la cible à mettre au point. Ce choix permet de respecter l’approche « minimaliste » souvent nécessaire dans le cas du développement bas niveau pour lequel un lien Ethernet fiable n’est pas toujours disponible. La connectique à utiliser est un câble de type null-modem (croisé).
    Au niveau des composants logiciels, l’utilisation de KGDB nécessite les éléments suivants :

    • Le paquetage KGDB.
    • Une version spéciale de GDB (soit gdbmod) adaptée à la gestion des modules dynamiques. Ce programme sera utilisé sur le poste de développement (souvent un PC x86 sous Linux). Une version binaire x86 de gdbmod est disponible ainsi que les patchs à appliquer aux sources de GDB. La version courante de gdbmod est la 2.4.
    • Le noyau Linux adapté à ce paquetage. Il est bien entendu nécessaire d’utiliser le noyau Linux standard (ou vanilla kernel) et non pas les noyaux fournis par les éditeurs de distributions. Nous rappelons que le noyau Linux standard est disponible sur http://www.kernel.org.

    Principes de fonctionnement

    Le fonctionnement du couple GDB/KGDB est assez proche de celui de GDB/GDBSERVER (en espace utilisateur). La mise au point de la partie statique du noyau Linux (correspondant habituellement au fichier compressé bzImage, version compressée du fichier vmlinux) sera possible à condition que le noyau ait été compilé avec l’option habituelle de mise au point, soit -g. Cette option est automatiquement ajoutée à la ligne de compilation du noyau si l’utilisation de KGDB est choisie dans la configuration du noyau (voir plus loin). Il faut noter que gdbmod nécessite l’utilisation de la version non compressée, soit vmlinux coté poste de développement. Outre la partie statique, le noyau Linux utilise de nombreux modules dynamiques. Ces modules peuvent provenir de l’arborescence standard du noyau ou bien être ajoutés a posteriori par l’utilisateur. Dans tous les cas, le module sera inséré dynamiquement en utilisant la commande insmod (ou modprobe). Il peut aussi être chargé automatiquement, mais, au final, ces mêmes commandes seront utilisées par le système Linux. Cela implique que GDB puisse traiter ce comportement dynamique, en l’occurrence gérer ces ajouts de modules. C’est la raison pour laquelle il est nécessaire d’utiliser une version modifiée de GDB (soit gdbmod) capable de traiter l’insertion dynamique de code. Dans le cas contraire, seule la mise au point de la partie statique du noyau sera possible, ce qui est assez limitatif. La structure d’un module Linux (fichier .ko) est assez proche de celle d’une bibliothèque partagée en espace utilisateur (.so). Afin d’informer manuellement GDB des adresses de chargement des différentes sections de code du module, on peut utiliser la directive GDB add-symbol-file. Elle prend en paramètre le nom du fichier .ko, l’adresse de base de la section .text et éventuellement celles des sections .bss et .data. Ces informations sont disponibles dans le fichier virtuel /sys/module/NomDuModule/sections. Cette solution est cependant assez peu pratique. Dans le cas des bibliothèques partagées (.so), GDB détecte bien entendu les adresses de chargement. La version spécifique de GDB fournie avec KGDB permet d’obtenir un comportement similaire pour les modules du noyau (.ko). Il suffit pour cela d’indiquer la liste des répertoires contenant les modules susceptibles d’êtres chargés, et ce, à l’aide de la directive set-solid-search-path suivie du nom du répertoire concerné. L’utilisation de ces techniques est largement détaillée dans les exemples en fin d’article.

    Installation de la configuration

    Comme nous l’avons précisé précédemment, la configuration à mettre en place est constituée de deux systèmes Linux reliés par un câble série RS-232.

    • Le premier système (hôte ou host) contient la version modifiée de GDB (soit gdbmod), les sources du noyau Linux modifié par le patch KGDB, ainsi que la chaîne de compilation.
    • Le deuxième système (cible ou target) exécute le noyau Linux et les modules à mettre au point. A priori, il ne contient pas de code source.

    Les paquetages à télécharger sur http://kgdb.linsyssoft.com/downloads.htm sont les suivants :

    • Le patch KGDB version 2.4, soit linux-2.6.15.5-kgdb-2.4.tar.bz2.
    • La version modifiée de GDB, soit gdbmod-2.4.bz2.

    La version 2.6.15.5 du noyau Linux est à télécharger à l’adresse
    http://www.kernel.org/pub/linux/kernel/v2.6.
    Par défaut, nous installerons les sources dans le répertoire /usr/src traditionnellement utilisé pour la compilation du noyau Linux. Pour installer le noyau modifié, nous effectuons tout d’abord l’extraction des sources du noyau et du patch KGDB soit :

    # cd /usr/src
    # tar xjvf /path/linux-2.6.15.5.tar.bz2
    # tar xjvf /path/linux-2.6.15.5-kgdb-2.4.tar.bz2

    On peut ensuite appliquer le patch KGDB aux sources du noyau. Pour ce faire, il faut suivre l’ordre des fichiers de patch défini dans le fichier series du répertoire linux-2.6.15.5-kgdb-2.4.

    # Patchdir: linux-2.6.15.5
    # Source: linux-2.6.15.5.tar.bz2
    core-lite.patch
    8250.patch
    netpoll_pass_skb_to_rx_hook.patch
    eth.patch
    i386-lite.patch
    powerpc-lite.patch
    mips-lite.patch
    ia64-lite.patch
    x86_64-no_context_hook.patch
    x86_64-lite.patch
    sh-lite.patch
    arm-lite.patch
    cfi_annotations.patch
    sysrq_bugfix.patch
    module.patch
    core.patch
    i386.patch
    powerpc.patch

    On applique donc les commandes suivantes :

    # cd /usr/src/linux-2.6.15.5
    # patch -p1 < ../linux-2.6.15.5-kgdb-2.4/core-lite.patch
    # patch -p1 < ../linux-2.6.15.5-kgdb-2.4/8250.patch
    ...
    # patch -p1 < ../linux-2.6.15.5-kgdb-2.4/powerpc.patch

    On peut dès à présent effectuer la configuration du noyau modifié en fonction de l’architecture matérielle. Si un fichier de configuration de noyau 2.6 (.config) existe déjà pour le système, on peut d’ores et déjà l’utiliser en copiant le fichier dans le répertoire des sources du noyau soit :

    # cd /usr/src/linux-2.6.15.5
    # cp /path/.config .

    La configuration du noyau s’effectue par la commande make menuconfig, ce qui provoque l’affichage de l’écran ci-dessous.

    /img-articles/lm/88/art-9/fig-1.jpg

    Figure 1 : Configuration du noyau

    On sélectionne ensuite l’entrée Kernel hacking, puis l’entrée Kernel debugging ce qui permet de valider l’entrée KGDB: kernel debugging with remote gdb. Au niveau de la configuration de KGDB, on doit valider les options décrites dans l’écran de la figure 2.
    A ce niveau, il est nécessaire de préciser :

    • Le mode de communication de KGDB avec GDB. Dans notre cas, nous utilisons le port série : KGDB: On generic serial port (8250)
    • La vitesse de la liaison (soit 115200 bits/s dans notre cas) et le numéro du port série (soit 0 dans notre cas, ce qui correspond à /dev/ttyS0).

    Il est également conseillé d’identifier ce noyau en lui affectant une « extra-version » significative comme précisé dans la figure 3. Dans notre cas, nous utilisons KGDB sur un portable Dell D800, d’où le nom de l’extension.
    On peut ensuite sauver la configuration (via le bouton Exit), puis compiler et installer le noyau par la procédure classique.

    # make
    # make modules_install
    # make install

    Le noyau compilé n’est pas exécuté sur le système de développement, mais sur la cible. Il faut donc copier les éléments nécessaires soit :

    • Le noyau compressé (vmlinuz ou bzImage) sur /boot ;
    • Le fichier System.map correspondant à la « carte » des symboles du noyau sur /boot ;

    /img-articles/lm/88/art-9/fig-2.jpg

     Figure 2. : Configuration de KGDB

    • L’arborescence des modules sur /lib/modules.

    La copie peut s’effectuer par NFS s’il est disponible. Dans le cas contraire, on peut simplement utiliser un outil de copie tel scp pour copier une archive compressée à l’aide de tar et gzip.

    # cd /boot
    # scp vmlinuz-2.6.15.5-kgdb_d800 root@192.168.3.121:/boot
    # scp System.map-2.6.15.5-kgdb_d800 root@192.168.3.121:/boot

    Du coté du système de développement, on utilise le fichier vmlinux (correspondant au noyau statique non compressé), les sources du noyau ainsi que les modules. Il reste à modifier la configuration du programme de démarrage sur la cible (ou bootloader). Dans notre cas, nous utilisons GRUB. La nouvelle entrée dans grub.conf (ou menu.lst) aura l’allure suivante :

    title           kernel 2.6.15.5 kgdb
    rootnoverify    (hd0,1)
    makeactive
    kernel          /boot/vmlinuz-2.6.15.5-kgdb_d800 root=/dev/hda2 kgdbwait
    savedefault
    boot

    On note l’utilisation de la directive kgdbwait qui indique au noyau d’attendre la connexion de GDB pour démarrer. D’autres commandes spécifiques à KGDB sont fréquemment utilisées.

    • La directive kgdb8250 qui permet de modifier les paramètres par défaut de la connexion série. Par exemple, on peut indiquer que l’on utilise un lien à 9600 bits/s sur le premier deuxième port série (1) en invoquant la commande kgdb8250=1,9600.
    • La directive kgdboe indiquant l’utilisation d’un lien Ethernet. Si la cible et l’hôte ont respectivement pour adresses IP 192.168.3.121 et 192.168.3.120, on utilisera la commande kgdboe=@192.168.3.121/,@192.168.3.120.

    Test du noyau compatible KGDB

    Pour tester le nouveau noyau, il suffit de démarrer la cible sur la nouvelle entrée GRUB. Le noyau s’arrête immédiatement après le message de démarrage.

     Uncompressing Linux... Ok, booting the kernel.

    Du coté du système de développement, on utilise gdbmod sur le fichier vmlinux à partir du répertoire des sources du noyau.

    # gdbmod-2.4 vmlinux
    GNU gdb 6.4
    Copyright 2005 Free Software Foundation, Inc.
    GDB is free software, covered by the GNU General Public License, and you are
    welcome to change it and/or distribute copies of it under certain conditions.
    Type «show copying» to see the conditions.
    There is absolutely no warranty for GDB.  Type «show warranty» for details.
    This GDB was configured as «i686-pc-linux-gnu»...Using host libthread_db library «/lib/tls/libthread_db.so.1».

    La connexion avec la cible s’effectue au travers de la commande target-remote. Ceci provoque la suspension de l’exécution afin de poser des points d’arrêt. Si l’on utilisait un lien Ethernet, la commande serait target remote udp:192.168.3.121:6443.

    (gdb) set remotebaud 115200
    (gdb) target remote /dev/ttyS0
    Remote debugging using /dev/ttyS0
    breakpoint () at kernel/kgdb.c:1888
    1888            atomic_set(&kgdb_setting_breakpoint, 0);
    (gdb)

    Sachant que le noyau utilise des modules (.ko), il est nécessaire d’indiquer à GDB les chemins d’accès à ces modules grâce à la commande solib-search-path. Les chemins sont séparés par le caractère « : ».

    (gdb) set solib-search-path /lib/modules/2.6.15.5 kgdb_d800/kernel/drivers/net:/lib/modules/2.6.15.5-kgdb_d800/kernel/drivers/cpufreq

    Dans notre exemple, nous pouvons poser un point d’arrêt dans la fonction do_mount() qui correspond au montage du root-filesystem du noyau. La commande continue (ou c en abrégé) provoque la suite de l’exécution du noyau.

    (gdb) b mount_root
    Breakpoint 1 at 0xc032aa9f: file init/do_mounts.c, line 385.
    (gdb) c
    Continuing.
    [New thread 1]
    [Switching to thread 1]
    
    Breakpoint 1, mount_root () at init/do_mounts.c:385
    385             create_dev(«/dev/root», ROOT_DEV, root_device_name);
    (gdb) i s
    #0  mount_root () at init/do_mounts.c:385
    #1  0xc032aba7 in prepare_namespace () at init/do_mounts.c:421
    #2  0xc01002d3 in init (unused=<value optimized out>) at init/main.c:705
    #3  0xc0100c89 in kernel_thread_helper () at arch/i386/kernel/process.c:316
    (gdb) c

    Dans la suite de l’exécution, nous pouvons noter que la liste des chemins d’accès aux modules n’est pas complète, ce qui provoque l’affichage des erreurs suivantes :

    /img-articles/lm/88/art-9/fig-3.jpg

    Figure 3 : Configuration de l’extra-version

    (gdb) c
    Continuing.
    [New thread 706]
    Error while mapping shared library sections:
    joydev.ko: Aucun fichier ou répertoire de ce type.
    Error while reading shared library symbols:
    joydev.ko: Aucun fichier ou répertoire de ce type.
    [New thread 726]

    La commande info sharedlibrary permet d’afficher la liste des modules réellement pris en compte par GDB.

    (gdb) info sharedlibrary
    From        To          Syms Read  Shared Object Library
                            No         joydev.ko
    0xf88c7000  0xf88d37a0  Yes        /lib/modules/2.6.15.5-kgdb_d800/kernel/drivers/net/tg3.ko
                            No         ipv6.ko
    0xf887d000  0xf887d898  Yes        /lib/modules/2.6.15.5-kgdb_d800/kernel/drivers/cpufreq/cpufreq_conservative.ko
    0xf88c4000  0xf88c46f0  Yes        /lib/modules/2.6.15.5-kgdb_d800/kernel/drivers/cpufreq/cpufreq_ondemand.ko
    0xf883b000  0xf883b03c  Yes        /lib/modules/2.6.15.5-kgdb_d800/kernel/drivers/cpufreq/cpufreq_powersave.ko
    he0xf8863000  0xf88634e8  Yes      /lib/modules/2.6.15.5-kgdb_d800/kernel/drivers/cpufreq/cpufreq_stats.ko
    (gdb)

    Mise au point d’un module externe

    La mise au point d’un module externe à l’arborescence du noyau est la tâche la plus fréquente des utilisateurs potentiels de KGDB. Dans ce chapitre, nous allons détailler la mise au point d’un module décrivant un exemple d’utilisation du pseudo système de fichier /proc. Le répertoire /proc est largement utilisé sur Linux pour l’obtention d’informations sur l’état du système. La plus simple utilisation de /proc est la suivante :

    $ cat /proc/version
    Linux version 2.6.12-14mdk (qateam@mercury.mandriva.com) (gcc version 4.0.1 (4.0.1-5mdk for Mandriva Linux release 2006.0)) #1 Tue Dec 20 15:45:27 MST 2005

    Il est cependant aisé d’écrire un module externe permettant d’utiliser /proc, en l’occurrence ajouter un sous-répertoire contenant des variables gérées par le module en question. Dans notre cas, l’insertion du module d’exemple ex2_mod crée une entrée /proc/ex2 contenant deux arguments id et num modifiables à l’insertion du module. Le code source du module a été écrit par Julien Gaulmin en 2001 dans le cadre d’une formation sur le noyau Linux. Pour les besoins de cet article, le code source a été adapté au noyau 2.6. Dans notre exemple, le point d’arrêt sera déclenché au moment ou l’utilisateur affiche le contenu du fichier /proc/ex2 via la commande cat. Le code source de l’exemple est décrit ci-dessous. La première partie concerne les fichiers d’en-tête ainsi que la description des variables que l’on peut passer lors de l’insertion du module par insmod.

    #include <linux/kernel.h>	/* printk() */
    #include <linux/module.h>	/* modules */
    #include <linux/init.h>		/* module_{init,exit}() */
    #include <linux/proc_fs.h>	/* proc fs */
    #include «ex.h»
    /*
     * Arguments
     */
    static char *id = «ex2_default»; /* ID-String of the module */
    static int num = 1234; /* A number */
    MODULE_DESCRIPTION(«Simple module with arguments and __/proc__ (ex2)»);
    MODULE_AUTHOR(«Julien Gaulmin, Alcove»);
    MODULE_PARM_DESC(id, «ID-String of the driver»);
    MODULE_PARM_DESC(num, «A number»);
    MODULE_PARM(id, «1-» __MODULE_STRING(MAX_ID_SIZE) «s»);
    MODULE_PARM(num, «i»);

    Cette partie contient la fonction ex2_get_info() sur laquelle nous poserons le point d’arrêt.

    /*
     * /proc handling
     */
    static int ex2_get_info(char *page, char **start, off_t off, int count)
    {
    	int len = 0;
    	len += sprintf(page + len, “ex2 arguments :\n”);
    	len += sprintf(page + len, «id=%s\n», id);
    	len += sprintf(page + len, “num=%d\n”, num);
    	return len;
    }

    Le reste du code concerne les fonctions associées aux appels module_init et module_exit. La fonction ex2_init() contient la procédure d’ajout du point d’entrée ex2 au répertoire /proc par la fonction create_proc_entry().

    /*
     * Init and Exit
     */
    static int __init ex2_init(void)
    {
    	struct proc_dir_entry *proc_entry;
    	printk(KERN_INFO «ex2 initialization\n»);
    	printk(KERN_INFO «ex2 arguments : id=%s, num=%d\n», id, num);
    	proc_entry = create_proc_entry(«ex2», 0, NULL);
    	if (proc_entry) {
    		proc_entry->get_info = ex2_get_info;
    	} else {
    		printk(KERN_ERR «Can’t create proc entry for ex2\n»);
    		return -EAGAIN;
    	}
    	return 0;
    }
    static void __exit ex2_exit(void)
    {
    	remove_proc_entry(«ex2», NULL);
    
    	printk(KERN_INFO “ex2 exit\n”);
    }
    /*
     * Module entry points
     */
    module_init(ex2_init);
    module_exit(ex2_exit);

    Le fichier Makefile adapté à la version 2.6 du noyau Linux est basé sur l’exemple donné par Joachim Nilsson (joachim.nilsson@member.fsf.org) dans le module2.6-howto. Par défaut, ce Makefile utilise l’option -g  nécessaire pour la mise au point du module par GDB. Il faut noter que le module doit être obligatoirement compilé dans l’environnement du noyau correspondant à KGDB (voir la variable KDIR dans le Makefile).

    MODULE_NAME = ex2_mod
    $(MODULE_NAME)-objs = ex2.o
    JUNK	= *~ *.bak DEADJOE
    # First pass, kernel Makefile reads module objects
    ifneq ($(KERNELRELEASE),)
    obj-m	:= $(MODULE_NAME).o
    EXTRA_CFLAGS += -I$(PWD)/../include
    # Second pass, the actual build.
    else
    #KDIR	:= /lib/modules/$(shell uname -r)/build
    KDIR	:= /usr/src/linux-2.6.15.5-kgdb
    PWD	:= $(shell pwd)
    all:
    	$(MAKE) -C $(KDIR) M=$(PWD) modules
    clean:
    	rm -f *~
    	$(MAKE) -C $(KDIR) M=$(PWD) clean

    On compile le module par la commande make ce qui produit le fichier ex2_mod.ko. Le fichier doit être copié sur la cible.

     # scp  ex2_mod.ko root@192.168.3.121:/root

    On peut alors démarrer la cible sur le noyau compatible KGDB. Du coté du système de développement, la procédure est similaire à celle du paragraphe précédent :

    # gdbmod-2.4 vmlinux
    GNU gdb 6.4
    Copyright 2005 Free Software Foundation, Inc.
    GDB is free software, covered by the GNU General Public License, and you are
    welcome to change it and/or distribute copies of it under certain conditions.
    Type «show copying» to see the conditions.
    There is absolutely no warranty for GDB.  Type «show warranty» for details.
    This GDB was configured as «i686-pc-linux-gnu»...Using host libthread_db library «/lib/tls/libthread_db.so.1».
    (gdb) set remotebaud 115200
    (gdb) target remote /dev/ttyS0
    Remote debugging using /dev/ttyS0
    breakpoint () at kernel/kgdb.c:1888
    1888            atomic_set(&kgdb_setting_breakpoint, 0);

    On doit ensuite définir le chemin d’accès au module, puis on pose le point d’arrêt sur la fonction à mettre au point. Le module n’étant pas encore chargé – puisque le système n’a pas encore totalement démarré – GDB indique que ce point d’arrêt est en attente (ou pending). On continue l’exécution du noyau jusqu’au démarrage complet du système cible.

    (gdb) set solib-search-path /home/pierre/tmp/2.6/ex2_proc
    (gdb) b ex2_get_info
    Function «ex2_get_info» not defined.
    Make breakpoint pending on future shared library load? (y or [n]) y
    Breakpoint 1 (ex2_get_info) pending.
    (gdb) c
    Continuing.

    Du coté de la cible, on peut alors insérer le module.

    # cd /root
    # insmod ex2_mod.ko

    Ce qui provoque l’affichage suivant sur le poste de développement (résolution du point d’arrêt).

    Breakpoint 2 at 0xf8866005: file /home/pierre/tmp/2.6/ex2_proc/ex2.c, line 93.
    Pending breakpoint «ex2_get_info» resolved
    [New thread 2360]
    [Switching to thread 2360]

    Du coté de la cible, on effectue la commande :

    # cat /proc/ex2

    ce qui provoque l’exécution du point d’arrêt et le « gel » du système. On peut exécuter la fonction en pas à pas.

     Breakpoint 2, ex2_exit () at /home/pierre/tmp/2.6/ex2_proc/ex2.c:93
    93         remove_proc_entry(«ex2», NULL);
    (gdb) n
    59         len += sprintf(page + len, “ex2 arguments :\n”);
    (gdb) n
    76         printk(KERN_INFO “ex2 arguments : id=%s, num=%d\n”, id, num);
    (gdb) n
    60         len += sprintf(page + len, “id=%s\n”, id);
    (gdb) n
    59         len += sprintf(page + len, “ex2 arguments :\n”);
    (gdb) n
    96      }
    (gdb) c
    Continuing.

    On arrive alors à l’affichage du résultat sur la cible :

    # ex2 arguments :
    id=ex2_default
    num=1234

    Conclusion

    La mise au point de code source dans l’espace du noyau Linux n’est pas aisée et la mise en place de GDB/KGDB est un peu ardue. Cependant, l’utilisation de ce composant peut rendre des services incomparables dans le cas d’un problème récalcitrant. L’utilisation de GDB est identique à l’espace utilisateur, ce qui est un avantage très appréciable.

    BIBLIOGRAPHIE  :

    • La page de KGDB sur http://kgdb.linsyssoft.com
    • Une présentation de Kprobes sur http://www.redhat.com/magazine/05mars005/features/kprobes
    • Un autre article concernant Kprobes sur http://www.linuxjournal.com/article/7905
    • La page de SystemTap sur http://sourceware.org/systemtap
    • Conférence de Stelian Pop sur la mise au point en espace noyau sur http://popies.net/conferences/kernel_debugging.pdf
    • La page UML sur http://user-mode-linux.sourceforge.net
    • La page Porting device drivers to the 2.6 kernel sur http://lwn.net/Articles/driver-porting/
    • L’article « Quelles solutions pour Linux embarqué ? » sur http://pficheux.free.fr/articles/lmf/hs24/sol_linux/sol_linux.pdf
    • Le code source de l’exemple du module ex2_mod sur http://pficheux.free.fr/articles/lmf/debug_kernel/ex2_mod.tgz

    Retrouvez cet article dans : Linux Magazine 88

    Posté par Pierre Ficheux (pficheux) | Signature : Pierre Ficheux | Article paru dans

    Laissez une réponse

    Vous devez avoir ouvert une session pour écrire un commentaire.

    • Il y a actuellement

    • 807 articles/billets en ligne.