GNU/Linux >> Tutoriels Linux >  >> Linux

Déboguer Linux avec ProcDump

L'appréciation croissante de Microsoft pour Linux et l'open source n'est pas un secret. La société a régulièrement augmenté ses contributions à l'open source au cours des dernières années, notamment en portant certains de ses logiciels et outils sur Linux. Fin 2018, Microsoft a annoncé qu'il transférait certains de ses outils Sysinternals vers Linux en open source, et ProcDump pour Linux était la première version de ce type.

Si vous avez travaillé sur Windows dans le débogage ou le dépannage, vous avez probablement entendu parler de Sysinternals. Il s'agit d'un ensemble d'outils "couteau suisse" qui aide les administrateurs système, les développeurs et les professionnels de la sécurité informatique à surveiller et à dépanner les environnements Windows.

Plus de ressources Linux

  • Aide-mémoire des commandes Linux
  • Aide-mémoire des commandes Linux avancées
  • Cours en ligne gratuit :Présentation technique de RHEL
  • Aide-mémoire sur le réseau Linux
  • Aide-mémoire SELinux
  • Aide-mémoire sur les commandes courantes de Linux
  • Que sont les conteneurs Linux ?
  • Nos derniers articles Linux

L'un des outils les plus populaires de Sysinternals est ProcDump. Comme son nom l'indique, il est utilisé pour vider la mémoire d'un processus en cours d'exécution dans un fichier core sur le disque. Ce fichier core peut ensuite être analysé à l'aide d'un débogueur pour comprendre l'état du processus au moment du vidage. Ayant déjà utilisé Sysinternals, j'étais curieux d'essayer le portage Linux de ProcDump.

Commencer avec ProcDump pour Linux

Pour essayer ProcDump pour Linux, vous devez télécharger l'outil et le compiler. (J'utilise Red Hat Enterprise Linux, bien que ces instructions devraient fonctionner de la même manière sur d'autres distributions Linux) :

$ cat /etc/redhat-release 
Red Hat Enterprise Linux release 8.2 (Ootpa)
$
$ uname -r
4.18.0-193.el8.x86_64
$

Tout d'abord, clonez le référentiel ProcDump pour Linux :

$ git clone https://github.com/microsoft/ProcDump-for-Linux.git
Cloning into 'ProcDump-for-Linux'...
remote: Enumerating objects: 40, done.
remote: Counting objects: 100% (40/40), done.
remote: Compressing objects: 100% (33/33), done.
remote: Total 414 (delta 14), reused 14 (delta 6), pack-reused 374
Receiving objects: 100% (414/414), 335.28 KiB | 265.00 KiB/s, done.
Resolving deltas: 100% (232/232), done.
$
$ cd ProcDump-for-Linux/
$
$ ls
azure-pipelines.yml  CONTRIBUTING.md  docs     INSTALL.md  Makefile    procdump.gif  src
CODE_OF_CONDUCT.md   dist             include  LICENSE     procdump.1  README.md     tests
$

Ensuite, construisez le programme en utilisant make . Il imprime l'interface de ligne de commande GCC exacte nécessaire pour compiler les fichiers sources :

$ make
rm -rf obj
rm -rf bin
rm -rf /root/ProcDump-for-Linux/pkgbuild
gcc -c -g -o obj/Logging.o src/Logging.c -Wall -I ./include -pthread -std=gnu99
gcc -c -g -o obj/Events.o src/Events.c -Wall -I ./include -pthread -std=gnu99
gcc -c -g -o obj/ProcDumpConfiguration.o src/ProcDumpConfiguration.c -Wall -I ./include -pthread -std=gnu99
gcc -c -g -o obj/Handle.o src/Handle.c -Wall -I ./include -pthread -std=gnu99
gcc -c -g -o obj/Process.o src/Process.c -Wall -I ./include -pthread -std=gnu99
gcc -c -g -o obj/Procdump.o src/Procdump.c -Wall -I ./include -pthread -std=gnu99
gcc -c -g -o obj/TriggerThreadProcs.o src/TriggerThreadProcs.c -Wall -I ./include -pthread -std=gnu99
gcc -c -g -o obj/CoreDumpWriter.o src/CoreDumpWriter.c -Wall -I ./include -pthread -std=gnu99
gcc -o bin/procdump obj/Logging.o obj/Events.o obj/ProcDumpConfiguration.o obj/Handle.o obj/Process.o obj/Procdump.o obj/TriggerThreadProcs.o obj/CoreDumpWriter.o -Wall -I ./include -pthread -std=gnu99
gcc -c -g -o obj/ProcDumpTestApplication.o tests/integration/ProcDumpTestApplication.c -Wall -I ./include -pthread -std=gnu99
gcc -o bin/ProcDumpTestApplication obj/ProcDumpTestApplication.o -Wall -I ./include -pthread -std=gnu99
$

La compilation crée deux nouveaux répertoires. Le premier est un obj/ répertoire, qui contient les fichiers objets créés lors de la compilation. Le deuxième répertoire (et le plus important) est bin/ , où se trouve le procdump compilé programme est enregistré. Il compile également un autre binaire de test appelé ProcDumpTestApplication :

$ ls obj/
CoreDumpWriter.o  Handle.o   ProcDumpConfiguration.o  ProcDumpTestApplication.o  TriggerThreadProcs.o
Events.o          Logging.o  Procdump.o               Process.o
$
$
$ ls bin/
procdump  ProcDumpTestApplication
$
$ file bin/procdump
bin/procdump: ELF 64-bit LSB executable, x86-64, version 1 (SYSV), dynamically linked, interpreter /lib64/ld-linux-x86-64.so.2, for GNU/Linux 3.2.0, BuildID[sha1]=6e8827db64835ea0d1f0941ac3ecff9ee8c06e6b, with debug_info, not stripped
$
$ file bin/ProcDumpTestApplication
bin/ProcDumpTestApplication: ELF 64-bit LSB executable, x86-64, version 1 (SYSV), dynamically linked, interpreter /lib64/ld-linux-x86-64.so.2, for GNU/Linux 3.2.0, BuildID[sha1]=c8fd86f53c07df142e52518815b2573d1c690e4e, with debug_info, not stripped
$

Avec cette configuration, chaque fois que vous exécutez le procdump utilitaire, vous devez vous déplacer dans le bin/ dossier. Pour le rendre disponible de n'importe où dans le système, exécutez make install . Cela copie le binaire dans le bin/ habituel répertoire, qui fait partie du $PATH de votre shell :

$ which procdump
/usr/bin/which: no procdump in (/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin)
$
$ make install
mkdir -p //usr/bin
cp bin/procdump //usr/bin
mkdir -p //usr/share/man/man1
cp procdump.1 //usr/share/man/man1
$
$ which procdump
/usr/bin/procdump
$

Avec l'installation, ProcDump fournit une page de manuel, à laquelle vous pouvez accéder avec man procdump :

$ man procdump
$

Exécuter ProcDump

Pour vider la mémoire d'un processus, vous devez fournir son ID de processus (PID) à ProcDump. Vous pouvez utiliser n'importe lequel des programmes ou démons en cours d'exécution sur votre machine. Pour cet exemple, je vais utiliser un petit programme C qui boucle indéfiniment. Compilez le programme et exécutez-le (pour quitter le programme, appuyez sur Ctrl +C , ou s'il s'exécute en arrière-plan, utilisez le kill commande avec le PID):

$ cat progxyz.c 
#include <stdio.h>

int main() {
        for (;;)
        {
                printf(".");
                sleep(1);
        }
        return 0;
}
$
$ gcc progxyz.c -o progxyz
$
$ ./progxyz &
[1] 350498
$

En exécutant le programme, vous pouvez trouver son PID en utilisant soit pgrep ou ps . Notez le PID :

$ pgrep progxyz
350498
$
$ ps -ef | grep progxyz
root      350498  345445  0 03:29 pts/1    00:00:00 ./progxyz
root      350508  347350  0 03:29 pts/0    00:00:00 grep --color=auto progxyz
$

Pendant que le processus de test est en cours d'exécution, invoquez procdump et fournir le PID. La sortie indique le nom du processus et le PID, signale qu'un Core dump a été généré et affiche son nom de fichier :

$ procdump -p 350498

ProcDump v1.1.1 - Sysinternals process dump utility
Copyright (C) 2020 Microsoft Corporation. All rights reserved. Licensed under the MIT license.
Mark Russinovich, Mario Hewardt, John Salem, Javid Habibi
Monitors a process and writes a dump file when the process exceeds the
specified criteria.

Process:                progxyz (350498)
CPU Threshold:          n/a
Commit Threshold:       n/a
Polling interval (ms):  1000
Threshold (s):  10
Number of Dumps:        1

Press Ctrl-C to end monitoring without terminating the process.

[03:30:00 - INFO]: Timed:
[03:30:01 - INFO]: Core dump 0 generated: progxyz_time_2020-06-24_03:30:00.350498
$

Listez le contenu du répertoire courant et vous devriez voir le nouveau fichier core. Le nom du fichier correspond à celui affiché par le procdump commande, et la date, l'heure et le PID y sont ajoutés :

$ ls -l progxyz_time_2020-06-24_03\:30\:00.350498 
-rw-r--r--. 1 root root 356848 Jun 24 03:30 progxyz_time_2020-06-24_03:30:00.350498
$
$ file progxyz_time_2020-06-24_03\:30\:00.350498
progxyz_time_2020-06-24_03:30:00.350498: ELF 64-bit LSB core file, x86-64, version 1 (SYSV), SVR4-style, from './progxyz', real uid: 0, effective uid: 0, real gid: 0, effective gid: 0, execfn: './progxyz', platform: 'x86_64'
$

Analyser le fichier core avec le débogueur de projet GNU

Pour voir si vous pouvez lire le fichier proc, appelez le débogueur de projet GNU (gdb ). N'oubliez pas de fournir le chemin du binaire de test afin que vous puissiez voir tous les noms de fonction sur la pile. Ici, bt (backtrace) montre que le sleep() fonction était en cours d'exécution lorsque le vidage a été effectué :

$ gdb -q ./progxyz ./progxyz_time_2020-06-24_03\:30\:00.350498 
Reading symbols from ./progxyz...(no debugging symbols found)...done.
[New LWP 350498]
Core was generated by `./progxyz'.
#0  0x00007fb6947e9208 in nanosleep () from /lib64/libc.so.6
Missing separate debuginfos, use: yum debuginfo-install glibc-2.28-101.el8.x86_64
(gdb) bt
#0  0x00007fb6947e9208 in nanosleep () from /lib64/libc.so.6
#1  0x00007fb6947e913e in sleep () from /lib64/libc.so.6
#2  0x00000000004005f3 in main ()
(gdb)

Qu'en est-il de gcore ?

Les utilisateurs de Linux seront prompts à souligner que Linux a déjà une commande appelée gcore , qui est livré avec la plupart des distributions Linux et fait exactement la même chose que ProcDump. C'est un argument valable. Si vous ne l'avez jamais utilisé, essayez ce qui suit pour vider le noyau d'un processus avec gcore . Exécutez à nouveau le programme de test, puis exécutez gcore , et fournissez le PID comme argument :

$ ./progxyz &
[1] 350664
$
$
$ pgrep progxyz
350664
$
$
$ gcore 350664
0x00007fefd3be2208 in nanosleep () from /lib64/libc.so.6
Saved corefile core.350664
[Inferior 1 (process 350664) detached]
$

gcore imprime un message indiquant qu'il a enregistré le noyau dans un fichier spécifique. Vérifiez le répertoire courant pour trouver ce fichier core et utilisez gdb à nouveau pour le charger :

$ 
$ ls -l  core.350664
-rw-r--r--. 1 root root 356848 Jun 24 03:34 core.350664
$
$
$ file core.350664
core.350664: ELF 64-bit LSB core file, x86-64, version 1 (SYSV), SVR4-style, from './progxyz', real uid: 0, effective uid: 0, real gid: 0, effective gid: 0, execfn: './progxyz', platform: 'x86_64'
$
$ gdb -q ./progxyz ./core.350664
Reading symbols from ./progxyz...(no debugging symbols found)...done.
[New LWP 350664]
Core was generated by `./progxyz'.
#0  0x00007fefd3be2208 in nanosleep () from /lib64/libc.so.6
Missing separate debuginfos, use: yum debuginfo-install glibc-2.28-101.el8.x86_64
(gdb) bt
#0  0x00007fefd3be2208 in nanosleep () from /lib64/libc.so.6
#1  0x00007fefd3be213e in sleep () from /lib64/libc.so.6
#2  0x00000000004005f3 in main ()
(gdb) q
$

Pour gcore pour fonctionner, vous devez vous assurer que les paramètres suivants sont en place. Tout d'abord, assurez-vous que le ulimit est défini pour les fichiers principaux ; s'il est défini sur 0 , les fichiers core ne seront pas générés. Deuxièmement, assurez-vous que /proc/sys/kernel/core_pattern possède les paramètres appropriés pour spécifier le modèle de base :

$ ulimit -c
unlimited
$

Devez-vous utiliser ProcDump ou gcore ?

Il existe plusieurs cas où vous préférerez peut-être utiliser ProcDump au lieu de gcore, et ProcDump a quelques fonctionnalités intégrées qui pourraient être utiles en général.

Attente de l'exécution d'un binaire de test

Que vous utilisiez ProcDump ou gcore, le processus de test doit être exécuté et en cours d'exécution afin que vous puissiez fournir un PID pour générer un fichier core. Mais ProcDump a une fonctionnalité qui attend qu'un binaire spécifique s'exécute; une fois qu'il trouve un binaire de test en cours d'exécution qui correspond à ce nom donné, il génère un fichier core pour ce binaire de test. Il peut être activé en utilisant le -w argument et le nom du programme au lieu d'un PID. Cette fonctionnalité peut être utile dans les cas où le programme de test se ferme rapidement.

Voilà comment cela fonctionne. Dans cet exemple, il n'y a pas de processus nommé progxyz en cours d'exécution :

$ pgrep progxyz 
$

Appelez procdump avec le -w commande pour le faire attendre. Depuis un autre terminal, invoquez le binaire de test progxyz :

$ procdump -w progxyz

ProcDump v1.1.1 - Sysinternals process dump utility
Copyright (C) 2020 Microsoft Corporation. All rights reserved. Licensed under the MIT license.
Mark Russinovich, Mario Hewardt, John Salem, Javid Habibi
Monitors a process and writes a dump file when the process exceeds the
specified criteria.

Process:                progxyz (pending)
CPU Threshold:          n/a
Commit Threshold:       n/a
Polling interval (ms):  1000
Threshold (s):  10
Number of Dumps:        1

Press Ctrl-C to end monitoring without terminating the process.

[03:39:23 - INFO]: Waiting for process 'progxyz' to launch...

Ensuite, depuis un autre terminal, invoquez le binaire de test progxyz  : 

$ ./progxyz &
[1] 350951
$

ProcDump détecte immédiatement que le binaire est en cours d'exécution et vide le fichier principal de ce binaire :

[03:39:23 - INFO]: Waiting for process 'progxyz' to launch...
[03:43:22 - INFO]: Found process with PID 350951
[03:43:22 - INFO]: Timed:
[03:43:23 - INFO]: Core dump 0 generated: progxyz_time_2020-06-24_03:43:22.350951
$


$ ls -l progxyz_time_2020-06-24_03\:43\:22.350951
-rw-r--r--. 1 root root 356848 Jun 24 03:43 progxyz_time_2020-06-24_03:43:22.350951
$
$ file progxyz_time_2020-06-24_03\:43\:22.350951
progxyz_time_2020-06-24_03:43:22.350951: ELF 64-bit LSB core file, x86-64, version 1 (SYSV), SVR4-style, from './progxyz', real uid: 0, effective uid: 0, real gid: 0, effective gid: 0, execfn: './progxyz', platform: 'x86_64'
$

Dumps de mémoire multiples

Une autre fonctionnalité importante de ProcDump est que vous pouvez spécifier le nombre de fichiers de base à générer en utilisant l'argument de ligne de commande -n <count> . L'intervalle de temps par défaut entre les core dumps est de 10 secondes, mais vous pouvez le modifier en utilisant le -s <sec> argument. Cet exemple utilise ProcDump pour effectuer trois vidages mémoire du binaire de test :

$ ./progxyz &
[1] 351014
$
$ procdump -n 3 -p 351014

ProcDump v1.1.1 - Sysinternals process dump utility
Copyright (C) 2020 Microsoft Corporation. All rights reserved. Licensed under the MIT license.
Mark Russinovich, Mario Hewardt, John Salem, Javid Habibi
Monitors a process and writes a dump file when the process exceeds the
specified criteria.

Process:                progxyz (351014)
CPU Threshold:          n/a
Commit Threshold:       n/a
Polling interval (ms):  1000
Threshold (s):  10
Number of Dumps:        3

Press Ctrl-C to end monitoring without terminating the process.

[03:45:20 - INFO]: Timed:
[03:45:21 - INFO]: Core dump 0 generated: progxyz_time_2020-06-24_03:45:20.351014
[03:45:31 - INFO]: Timed:
[03:45:32 - INFO]: Core dump 1 generated: progxyz_time_2020-06-24_03:45:31.351014
[03:45:42 - INFO]: Timed:
[03:45:44 - INFO]: Core dump 2 generated: progxyz_time_2020-06-24_03:45:42.351014
$
$ ls -l progxyz_time_2020-06-24_03\:45\:*
-rw-r--r--. 1 root root 356848 Jun 24 03:45 progxyz_time_2020-06-24_03:45:20.351014
-rw-r--r--. 1 root root 356848 Jun 24 03:45 progxyz_time_2020-06-24_03:45:31.351014
-rw-r--r--. 1 root root 356848 Jun 24 03:45 progxyz_time_2020-06-24_03:45:42.351014
$

Dump de mémoire basé sur l'utilisation du processeur et de la mémoire

ProcDump vous permet également de déclencher un vidage de mémoire lorsqu'un binaire ou un processus de test atteint un certain seuil de CPU ou de mémoire. La page de manuel de ProcDump montre les arguments de ligne de commande à utiliser lors de l'appel de ProcDump :

-C          Trigger core dump generation when CPU exceeds or equals specified value (0 to 100 * nCPU)
-c          Trigger core dump generation when CPU is less than specified value (0 to 100 * nCPU)
-M          Trigger core dump generation when memory commit exceeds or equals specified value (MB)
-m          Trigger core dump generation when when memory commit is less than specified value (MB)
-T          Trigger when thread count exceeds or equals specified value.
-F          Trigger when filedescriptor count exceeds or equals specified value.
-I          Polling frequency in milliseconds (default is 1000)

Par exemple, vous pouvez demander à ProcDump de vider le cœur lorsque l'utilisation du processeur du PID dépasse 70 % :

procdump -C 70 -n 3 -p 351014

Conclusion

ProcDump est un ajout intéressant à la longue liste de programmes Windows portés sur Linux. Non seulement il fournit des options d'outils supplémentaires aux utilisateurs de Linux, mais il peut également permettre aux utilisateurs de Windows de se sentir plus à l'aise lorsqu'ils travaillent sur Linux.


Linux
  1. Identifier les propriétés de sécurité sous Linux à l'aide de checksec

  2. Exemples d'utilisation de la commande dmsetup sous Linux

  3. Exemple d'utilisation de getnstimeofday dans le noyau Linux

  4. Déplacer un dossier sous Linux à l'aide de la commande mv

  5. IPC utilisant des signaux sur Linux

Comment créer un serveur CS:GO sur un VPS Linux

Comment afficher les utilisateurs de MySQL avec Linux

Écriture sans distraction sur Linux à l'aide de FocusWriter

Installer MongoDB à l'aide de Vagrant sous Linux

Utilisation de la commande Watch sous Linux

Utilisation de cut sur Linux Terminal