web-dev-qa-db-fra.com

Débogage en direct du noyau Linux, comment cela se fait et quels outils sont utilisés?

Quelles sont les méthodes et les outils les plus courants et pourquoi pas rares utilisés pour effectuer un débogage en direct sur le noyau Linux? Je sais que Linus par exemple. est contre ce type de débogage pour le noyau Linux ou c'était le moins et donc rien n'a été fait dans ce sens au cours de ces années, mais honnêtement, beaucoup de temps s'est écoulé depuis 2000 et je suis intéressé si cette mentalité a changé en ce qui concerne le projet Linux et quelles méthodes actuelles sont actuellement utilisées pour faire du débogage en direct sur le noyau Linux (local ou distant)?

Les références aux procédures pas à pas et aux didacticiels sur les techniques et outils mentionnés sont les bienvenues.

52
Shinnok

Une autre option consiste à utiliser ICE /contrôleur JTAG et GDB. Cette solution "hardware" est particulièrement utilisée avec les systèmes embarqués,

mais par exemple Qemu offre des fonctionnalités similaires:

  • démarrez qemu avec un stub gdb 'remote' qui écoute sur 'localhost: 1234': qemu -s ...,

  • puis avec GDB vous ouvrez le fichier du noyau vmlinux compilé avec les informations de débogage (vous pouvez jeter un oeil à un thread de liste de diffusion this où ils discutent de la non optimisation du noyau).

  • connecter GDB et Qemu: target remote localhost:1234

  • voir votre live noyau:

    (gdb) where
    #0  cpu_v7_do_idle () at Arch/arm/mm/proc-v7.S:77
    #1  0xc0029728 in Arch_idle () atarm/mach-realview/include/mach/system.h:36
    #2  default_idle () at arm/kernel/process.c:166
    #3  0xc00298a8 in cpu_idle () at Arch/arm/kernel/process.c:199
    #4  0xc00089c0 in start_kernel () at init/main.c:713
    

malheureusement, le débogage de l'espace utilisateur n'est pas possible jusqu'à présent avec GDB (pas d'informations sur la liste des tâches, pas de MMU reprogrammation pour voir différents contextes de processus, ...), mais si vous restez dans l'espace noyau , c'est assez pratique.

  • info threads vous donnera la liste et les états des différents CPU

MODIFIER:

Vous pouvez obtenir plus de détails sur la procédure dans ce PDF:

Débogage de systèmes Linux utilisant GDB et QEM .

28
Kevin

Lors du débogage du noyau Linux, nous pouvons utiliser plusieurs outils, par exemple, les débogueurs (KDB, KGDB), le vidage en cas de plantage (LKCD), la trousse d'outils de traçage (LTT, LTTV, LTTng), les instruments de noyau personnalisés (dprobes, kprobes). Dans la section suivante, j'ai essayé de résumer la plupart d'entre eux, j'espère que cela vous aidera.

[~ # ~] lkcd [~ # ~] (Linux Kernel Crash Dump) permet au système Linux d'écrire le contenu de sa mémoire lors d'un crash se produit. Ces journaux peuvent être analysés plus en détail pour la cause première de l'accident. Ressources concernant LKCD

Oups lorsque le noyau détecte un problème, il affiche un message Oops. Un tel message est généré par des instructions printk dans le gestionnaire de défauts (Arch/*/kernel/traps.c). Un tampon en anneau dédié dans le noyau utilisé par les instructions printk. Oops contient des informations telles que le CPU où le Oops s'est produit le, contenu des registres du CPU, nombre d'Oops, description, trace de pile et autres. Ressources concernant le Oups du noyau

Sondes dynamiques est l'un des outils de débogage populaires pour Linux développé par IBM. Cet outil permet de placer une "sonde" à presque n'importe quel endroit du système, à la fois dans l'espace utilisateur et dans le noyau. La sonde consiste en du code (écrit dans un langage spécialisé, orienté pile) qui est exécuté lorsque le contrôle atteint le point donné. Ressources concernant Dynamic Probe répertoriées ci-dessous

Linux Trace Toolkit est un correctif du noyau et un ensemble d'utilitaires associés qui permettent le traçage des événements dans le noyau. La trace comprend des informations de synchronisation et peut créer une image raisonnablement complète de ce qui s'est produit au cours d'une période donnée. Ressources de LTT, LTT Viewer et LTT Next Generation

[~ # ~] memwatch [~ # ~] est un outil de détection d'erreur de mémoire open source. Il fonctionne en définissant MEMWATCH dans l'instruction gcc et en ajoutant un fichier d'en-tête à notre code. Grâce à cela, nous pouvons suivre les fuites de mémoire et les corruptions de mémoire. Ressources concernant MEMWATCH

ftrace est un bon framework de traçage pour le noyau Linux. ftrace trace les opérations internes du noyau. Cet outil inclus dans le noyau Linux en 2.6.27. Avec ses divers plugins traceurs, ftrace peut être ciblé sur différents points de trace statiques, tels que la planification d'événements, les interruptions, les E/S mappées en mémoire, les transitions d'état d'alimentation du processeur et les opérations liées aux systèmes de fichiers et à la virtualisation. En outre, le suivi dynamique des appels de fonction du noyau est disponible, éventuellement restreint à un sous-ensemble de fonctions en utilisant des globes, et avec la possibilité de générer des graphiques d'appels et de fournir l'utilisation de la pile. Vous pouvez trouver un bon tutoriel de ftrace sur https://events.linuxfoundation.org/slides/2010/linuxcon_japan/linuxcon_jp2010_rostedt.pdf

ltrace est un utilitaire de débogage sous Linux, utilisé pour afficher les appels qu'une application d'espace utilisateur fait aux bibliothèques partagées. Cet outil peut être utilisé pour tracer tout appel de fonction de bibliothèque dynamique. Il intercepte et enregistre les appels de bibliothèque dynamique qui sont appelés par le processus exécuté et les signaux qui sont reçus par ce processus. Il peut également intercepter et imprimer les appels système exécutés par le programme.

[~ # ~] kdb [~ # ~] est le débogueur intégré au noyau Linux. KDB suit une interface simpliste de style Shell. Nous pouvons l'utiliser pour inspecter la mémoire, les registres, les listes de processus, dmesg et même définir des points d'arrêt pour qu'ils s'arrêtent à un certain emplacement. Grâce à KDB, nous pouvons définir des points d'arrêt et exécuter un contrôle de base de l'exécution du noyau ( Bien que KDB ne soit pas un débogueur au niveau source). Plusieurs ressources utiles concernant KDB

[~ # ~] kgdb [~ # ~] est destiné à être utilisé comme débogueur de niveau source pour le noyau Linux. Il est utilisé avec gdb pour déboguer un noyau Linux. Deux machines sont nécessaires pour utiliser kgdb. L'une de ces machines est une machine de développement et l'autre est la machine cible. Le noyau à déboguer s'exécute sur la machine cible. On s'attend à ce que gdb puisse être utilisé pour "pénétrer" dans le noyau pour inspecter la mémoire, les variables et consulter les informations de la pile d'appels de la même manière qu'un développeur d'application utiliserait gdb pour déboguer une application. Il est possible de placer des points d'arrêt dans le code du noyau et d'effectuer des étapes d'exécution limitées. Plusieurs ressources utiles concernant KGDB

21

Selon le wiki , kgdb a été fusionné dans le noyau dans 2.6.26 ce qui est au cours des dernières années. kgdb est un débogueur distant , donc vous activez-le dans votre noya puis vous y attachez gdb. Je dis en quelque sorte car il semble y avoir beaucoup d'options - voir connexion gdb . Étant donné que kgdb est maintenant dans l'arborescence source, je dirais que c'est ce que vous souhaitez utiliser.

Il semble donc que Linus ait cédé. Cependant, je voudrais souligner son argument - vous devez savoir ce que vous faites et bien connaître le système. C'est la terre du noyau. Si quelque chose se passe mal, vous n'obtenez pas segfault, vous obtenez quoi que ce soit d'un problème obscur plus tard à l'ensemble du système qui tombe. Voilà des dragons. Procédez avec prudence, vous avez été prévenu.

20
user257111

KGDB + QEMU pas à pas

KGDB est un sous-système de noyau qui vous permet de déboguer le noyau lui-même à partir d'un GDB hôte.

Mon exemple QEMU + Buildroot est un bon moyen d'en avoir un aperçu sans matériel réel: https://github.com/cirosantilli/linux-kernel-module-cheat/tree/1969cd6f8d30dace81d9848c6bacbb8bad9dacd8#kgdb

Avantages et inconvénients par rapport aux autres méthodes:

  • avantage par rapport à QEMU:
    • vous n'avez souvent pas d'émulation logicielle pour votre appareil, car les fournisseurs de matériel n'aiment pas publier de modèles logiciels précis pour leurs appareils
    • véritable matériel plus rapide que QEMU
  • avantage par rapport à JTAG: pas besoin de matériel JTAG supplémentaire, plus facile à configurer
  • inconvénients par rapport à QEMU et JTAG: moins de visibilité et plus intrusif. KGDB s'appuie sur certaines parties du noyau qui fonctionnent pour pouvoir communiquer avec l'hôte. Donc par exemple ça tombe en panne, vous ne pouvez pas voir la séquence de démarrage.

Les principales étapes sont les suivantes:

  1. Compilez le noyau avec:

    CONFIG_DEBUG_KERNEL=y
    CONFIG_DEBUG_INFO=y
    
    CONFIG_CONSOLE_POLL=y
    CONFIG_KDB_CONTINUE_CATASTROPHIC=0
    CONFIG_KDB_DEFAULT_ENABLE=0x1
    CONFIG_KDB_KEYBOARD=y
    CONFIG_KGDB=y
    CONFIG_KGDB_KDB=y
    CONFIG_KGDB_LOW_LEVEL_TRAP=y
    CONFIG_KGDB_SERIAL_CONSOLE=y
    CONFIG_KGDB_TESTS=y
    CONFIG_KGDB_TESTS_ON_BOOT=n
    CONFIG_MAGIC_SYSRQ=y
    CONFIG_MAGIC_SYSRQ_DEFAULT_ENABLE=0x1
    CONFIG_SERIAL_KGDB_NMI=n
    

    La plupart d'entre eux ne sont pas obligatoires, mais c'est ce que j'ai testé.

  2. Ajoutez à votre commande QEMU:

    -append 'kgdbwait kgdboc=ttyS0,115200' \
    -serial tcp::1234,server,nowait
    
  3. Exécutez GDB avec à partir de la racine de l'arborescence des sources du noyau Linux avec:

    gdb -ex 'file vmlinux' -ex 'target remote localhost:1234'
    
  4. Dans GDB:

    (gdb) c
    

    et le démarrage devrait se terminer.

  5. Dans QEMU:

    echo g > /proc/sysrq-trigger
    

    Et GDB devrait se casser.

  6. Maintenant que nous avons terminé, vous pouvez utiliser GDB comme d'habitude:

    b sys_write
    c
    

Testé dans Ubuntu 14.04.

KGDB + Raspberry Pi

La même configuration exacte que ci-dessus a presque fonctionné sur un Raspberry Pi 2, Raspbian Jessie 2016-05-27.

Il vous suffit d'apprendre à faire les étapes QEMU sur le Pi, qui sont facilement googlables:

  • ajouter les options de configuration et recompiler le noyau comme expliqué sur https://www.raspberrypi.org/documentation/linux/kernel/building.md Il y avait malheureusement des options manquantes sur la construction du noyau par défaut, notamment pas déboguer les symboles, donc la recompilation est nécessaire.

  • éditer cmdline.txt de la partition de démarrage et ajoutez:

    kgdbwait kgdboc=ttyAMA0,115200
    
  • connectez gdb à la série avec:

    arm-linux-gnueabihf-gdb -ex 'file vmlinux' -ex 'target remote /dev/ttyUSB0'
    

    Si vous n'êtes pas familier avec la série, consultez ceci: https://www.youtube.com/watch?v=da5Q7xL_OTo Tout ce dont vous avez besoin est un adaptateur bon marché comme celui-ci . Assurez-vous que vous pouvez obtenir un shell via la série pour vous assurer qu'il fonctionne avant d'essayer KGDB.

  • faire:

    echo g | Sudo tee /proc/sysrq-trigger
    

    depuis l'intérieur d'une session SSH, car la série est déjà prise par GDB.

Avec cette configuration, j'ai pu mettre un point d'arrêt dans sys_write, suspendre l'exécution du programme, répertorier la source et continuer.

Cependant, parfois quand je faisais next dans sys_write GDB vient de se bloquer et d'imprimer ce message d'erreur plusieurs fois:

Ignoring packet error, continuing...

donc je ne sais pas si quelque chose ne va pas dans ma configuration, ou si cela est prévu en raison de ce que fait un processus d'arrière-plan dans l'image Raspbian plus complexe.

On m'a également dit d'essayer de désactiver le multitraitement avec les options de démarrage Linux, mais je ne l'ai pas encore essayé.

En fait, la blague est que Linux a un débogueur dans le noyau depuis le 2.2.12, xmon, mais uniquement pour l'architecture powerpc (en fait c'était ppc à l'époque).

Ce n'est pas un débogueur au niveau source, et il est presque entièrement non documenté, mais quand même.

http://lxr.linux.no/linux-old+v2.2.12/Arch/ppc/xmon/xmon.c#L119

4
mpe

Procédure pas à pas QEMU + GDB testée sur l'hôte Ubuntu 16.10

Pour démarrer rapidement à partir de zéro, j'ai fait un exemple minimal entièrement automatisé de QEMU + Buildroot sur: https://github.com/cirosantilli/linux-kernel-module-cheat Les principales étapes sont décrites ci-dessous.

Obtenez d'abord un système de fichiers racine rootfs.cpio.gz. Si vous en avez besoin, envisagez:

Puis sur le noyau Linux:

git checkout v4.9
make mrproper
make x86_64_defconfig
cat <<EOF >.config-fragment
CONFIG_DEBUG_INFO=y
CONFIG_DEBUG_KERNEL=y
CONFIG_GDB_SCRIPTS=y
EOF
./scripts/kconfig/merge_config.sh .config .config-fragment
make -j"$(nproc)"
qemu-system-x86_64 -kernel Arch/x86/boot/bzImage \
                   -initrd rootfs.cpio.gz -S -s

Sur un autre terminal, en supposant que vous souhaitez démarrer le débogage à partir de start_kernel:

gdb \
    -ex "add-auto-load-safe-path $(pwd)" \
    -ex "file vmlinux" \
    -ex 'set Arch i386:x86-64:intel' \
    -ex 'target remote localhost:1234' \
    -ex 'break start_kernel' \
    -ex 'continue' \
    -ex 'disconnect' \
    -ex 'set Arch i386:x86-64' \
    -ex 'target remote localhost:1234'

et nous avons terminé !!

Pour les modules du noyau, voir: Comment déboguer les modules du noyau Linux avec QEMU?

Pour Ubuntu 14.04, GDB 7.7.1, hbreak était nécessaire, break les points d'arrêt logiciels ont été ignorés. Ce n'est plus le cas en 16.10. Voir aussi: https://bugs.launchpad.net/ubuntu/+source/qemu-kvm/+bug/901944

Le désordre disconnect et ce qui vient après doivent contourner l'erreur:

Remote 'g' packet reply is too long: 000000000000000017d11000008ef4810120008000000000fdfb8b07000000000d352828000000004040010000000000903fe081ffffffff883fe081ffffffff00000000000e0000ffffffffffe0ffffffffffff07ffffffffffffffff9fffff17d11000008ef4810000000000800000fffffffff8ffffffffff0000ffffffff2ddbf481ffffffff4600000010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000007f0300000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000801f0000

Sujets associés:

Voir également:

Limitations connues:

En tant que personne qui écrit beaucoup de code du noyau, je dois dire que je n'ai jamais utilisé kgdb, et que j'utilise rarement kprobes, etc.

C'est encore souvent la meilleure approche pour ajouter des printks stratégiques. Dans les noyaux plus récents trace_printk est un bon moyen de le faire sans spammer le dmesg.

3
mpe

Mode utilisateur Linux (UML)

https://en.wikipedia.org/wiki/User-mode_Linux

Une autre virtualisation une autre méthode qui permet le débogage d'étape du code du noyau.

UML est très ingénieux: il est implémenté comme Arch, tout comme x86, mais au lieu d'utiliser des instructions de bas niveau, il implémente les fonctions Arch avec des appels système userland.

Le résultat est que vous pouvez exécuter le code du noyau Linux en tant que processus utilisateur sur un hôte Linux!

Créez d'abord un rootfs et exécutez-le comme indiqué sur: https://unix.stackexchange.com/questions/73203/how-to-create-rootfs-for-user-mode-linux-on-Fedora-18/372207 # 372207

um defconfig définit CONFIG_DEBUG_INFO=y par défaut (ouaip, c'est une chose de développement), donc ça va.

Sur invité:

i=0
while true; do echo $i; i=$(($i+1)); done

Sur l'hôte dans un autre shell:

ps aux | grep ./linux
gdb -pid "$pid"

Dans GDB:

break sys_write
continue
continue

Et maintenant, vous contrôlez le nombre à partir de GDB et pouvez voir la source comme prévu.

Avantages:

  • entièrement contenu dans l'arborescence principale du noyau Linux
  • plus léger que l'émulation système complète de QEMU

Les inconvénients:

Voir aussi: https://unix.stackexchange.com/questions/127829/why-would-someone-want-to-run-usermode-linux-uml

Vous avez tort, la kgdb fonctionne toujours bien pour le dernier noyau, vous devez vous occuper de la configuration du noyau de l'image divisée, de l'optimisation de la randomisation.

kgdb sur le port série est inutile car aucun ordinateur ne supporte aujourd'hui DB9 sur un port série de la carte mère, le port série USB ne prend pas en charge le mode d'interrogation.

Le nouveau jeu est kgdboe, voici la trace du journal:

ce qui suit est la machine hôte, vmlinux est de la machine cible

root@Thinkpad-T510:~/KGDBOE# gdb vmlinux
Reading symbols from vmlinux...done.
(gdb) target remote udp:192.168.1.22:31337
1077    kernel/debug/debug_core.c: No such file or directory.
(gdb) l oom_kill_process 
828 mm/oom_kill.c: No such file or directory.
(gdb) l oom_kill_process 
828 in mm/oom_kill.c
(gdb) break oom_kill_process
Breakpoint 1 at 0xffffffff8119e0c0: file mm/oom_kill.c, line 833.
(gdb) c
Continuing.
[New Thread 1779]
[New Thread 1782]
[New Thread 1777]
[New Thread 1778]
[New Thread 1780]
[New Thread 1781]
[Switching to Thread 1779]

Thread 388 hit Breakpoint 1, oom_kill_process (oc=0xffffc90000d93ce8, message=0xffffffff82098fbc "Out of memory")
at mm/oom_kill.c:833
833 in mm/oom_kill.c
(gdb) s
834 in mm/oom_kill.c
(gdb) 

Sur une machine cible homologue, voici comment l'obtenir et être capturé par la machine hôte

#swapoff -a
#stress -m 4 --vm-bytes=500m
0
unhmble