Il crescente apprezzamento di Microsoft per Linux e l'open source non è un segreto. L'azienda ha costantemente aumentato i suoi contributi all'open source negli ultimi anni, incluso il porting di alcuni dei suoi software e strumenti su Linux. Alla fine del 2018, Microsoft ha annunciato che stava portando alcuni dei suoi strumenti Sysinternals su Linux come open source e ProcDump per Linux è stata la prima versione di questo tipo.
Se hai lavorato su Windows per il debug o la risoluzione dei problemi, probabilmente hai sentito parlare di Sysinternals. Si tratta di un set di strumenti "coltellino svizzero" che aiuta amministratori di sistema, sviluppatori e professionisti della sicurezza IT a monitorare e risolvere i problemi degli ambienti Windows.
Più risorse Linux
- Comandi Linux cheat sheet
- Cheat sheet sui comandi avanzati di Linux
- Corso online gratuito:Panoramica tecnica RHEL
- Cheat sheet della rete Linux
- Cheat sheet di SELinux
- Cheat sheet dei comandi comuni di Linux
- Cosa sono i container Linux?
- I nostri ultimi articoli su Linux
Uno degli strumenti più popolari di Sysinternals è ProcDump. Come suggerisce il nome, viene utilizzato per eseguire il dump della memoria di un processo in esecuzione in un file core su disco. Questo file principale può quindi essere analizzato utilizzando un debugger per comprendere lo stato del processo quando è stato eseguito il dump. Avendo usato Sysinternals in precedenza, ero curioso di provare il port Linux di ProcDump.
Inizia con ProcDump per Linux
Per provare ProcDump per Linux, devi scaricare lo strumento e compilarlo. (Sto usando Red Hat Enterprise Linux, anche se queste istruzioni dovrebbero funzionare allo stesso modo su altre distribuzioni Linux):
$ cat /etc/redhat-release
Red Hat Enterprise Linux release 8.2 (Ootpa)
$
$ uname -r
4.18.0-193.el8.x86_64
$
Innanzitutto, clona il repository ProcDump per 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
$
Quindi, crea il programma usando make
. Stampa l'esatta interfaccia della riga di comando di GCC necessaria per compilare i file sorgente:
$ 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 crea due nuove directory. Il primo è un obj/
directory, che contiene i file oggetto creati durante la compilazione. La seconda (e più importante) directory è bin/
, che è dove viene compilato il procdump
il programma è memorizzato. Compila anche un altro binario di test chiamato 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
$
Con questa configurazione, ogni volta che esegui procdump
utilità, devi spostarti nel bin/
cartella. Per renderlo disponibile da qualsiasi punto all'interno del sistema, esegui make install
. Questo copia il binario nel solito bin/
directory, che fa parte del $PATH
della tua 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
$
Con l'installazione, ProcDump fornisce una pagina man, a cui puoi accedere con man procdump
:
$ man procdump
$
Esegui ProcDump
Per eseguire il dump della memoria di un processo, è necessario fornire il suo ID processo (PID) a ProcDump. Puoi usare qualsiasi programma o demone in esecuzione sulla tua macchina. Per questo esempio, userò un minuscolo programma C che si ripete all'infinito. Compila il programma ed eseguilo (per uscire dal programma, premi Ctrl +C , o se è in esecuzione in background, usa il kill
comando con il PID):
$ cat progxyz.c
#include <stdio.h>
int main() {
for (;;)
{
printf(".");
sleep(1);
}
return 0;
}
$
$ gcc progxyz.c -o progxyz
$
$ ./progxyz &
[1] 350498
$
Eseguendo il programma, puoi trovare il suo PID usando pgrep
o ps
. Prendere nota del 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
$
Mentre il processo di test è in esecuzione, invoca procdump
e fornire il PID. L'output indica il nome del processo e il PID, segnala che un Core dump
è stato generato e mostra il nome del file:
$ 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
$
Elenca il contenuto della directory corrente e dovresti vedere il nuovo file core. Il nome del file corrisponde a quello mostrato da procdump
comando e la data, l'ora e il PID vengono aggiunti ad esso:
$ 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'
$
Analizza il file principale con GNU Project Debugger
Per vedere se riesci a leggere il file proc, richiama GNU Project Debugger (gdb
). Ricordarsi di fornire il percorso del binario di test in modo da poter vedere tutti i nomi delle funzioni nello stack. Qui, bt
(backtrace) mostra che sleep()
la funzione era in esecuzione quando è stato eseguito il dump:
$ 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)
E gcore?
Gli utenti Linux si affretteranno a sottolineare che Linux ha già un comando chiamato gcore
, che viene fornito con la maggior parte delle distribuzioni Linux e fa esattamente la stessa cosa di ProcDump. Questo è un argomento valido. Se non l'hai mai usato, prova quanto segue per scaricare il core di un processo con gcore
. Esegui di nuovo il programma di test, quindi esegui gcore
e fornisci il PID come argomento:
$ ./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
stampa un messaggio che dice di aver salvato il core in un file specifico. Controlla la directory corrente per trovare questo file principale e usa gdb
di nuovo per caricarlo:
$
$ 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
$
Per gcore
per funzionare, è necessario assicurarsi che le seguenti impostazioni siano a posto. Innanzitutto, assicurati che ulimit
è impostato per i file core; se è impostato su 0
, i file core non verranno generati. In secondo luogo, assicurati che /proc/sys/kernel/core_pattern
ha le impostazioni corrette per specificare il pattern principale:
$ ulimit -c
unlimited
$
Dovresti usare ProcDump o gcore?
Ci sono diversi casi in cui potresti preferire l'uso di ProcDump invece di gcore e ProcDump ha alcune funzionalità integrate che potrebbero essere utili in generale.
In attesa dell'esecuzione di un binario di test
Indipendentemente dal fatto che utilizzi ProcDump o gcore, il processo di test deve essere eseguito e in uno stato di esecuzione in modo da poter fornire un PID per generare un file core. Ma ProcDump ha una funzione che attende l'esecuzione di un binario specifico; una volta trovato un binario di test in esecuzione che corrisponde a quel nome, genera un file core per quel binario di test. Può essere abilitato usando il -w
argomento e il nome del programma invece di un PID. Questa funzione può essere utile nei casi in cui il programma di test si chiude rapidamente.
Ecco come funziona. In questo esempio, non esiste un processo denominato progxyz
in esecuzione:
$ pgrep progxyz
$
Richiama procdump
con il -w
comando di tenerlo in attesa. Da un altro terminale, invoca il binario di 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...
Quindi, da un altro terminale, invoca il binario di test progxyz
:
$ ./progxyz &
[1] 350951
$
ProcDump rileva immediatamente che il binario è in esecuzione e scarica il file principale per questo binario:
[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'
$
Dump più core
Un'altra importante caratteristica di ProcDump è che puoi specificare quanti file core generare usando l'argomento della riga di comando -n <count>
. L'intervallo di tempo predefinito tra i core dump è di 10 secondi, ma puoi modificarlo utilizzando -s <sec>
discussione. Questo esempio usa ProcDump per prendere tre core dump del binario di 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
$
Core dump basato sull'utilizzo della CPU e della memoria
ProcDump consente inoltre di attivare un core dump quando un binario di prova o un processo raggiunge una determinata soglia di CPU o memoria. La pagina man di ProcDump mostra gli argomenti della riga di comando da usare quando si invoca 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)
Ad esempio, puoi chiedere a ProcDump di eseguire il dump del core quando l'utilizzo della CPU del PID specificato supera il 70%:
procdump -C 70 -n 3 -p 351014
Conclusione
ProcDump è un'interessante aggiunta alla lunga lista di programmi Windows portati su Linux. Non solo fornisce ulteriori opzioni di strumenti agli utenti Linux, ma può anche far sentire gli utenti Windows più a loro agio quando lavorano su Linux.