GNU/Linux >> Linux Esercitazione >  >> Linux

Creazione e debug dei file di dump di Linux

Crash dump, memory dump, core dump, system dump... producono tutti lo stesso risultato:un file contenente lo stato della memoria di un'applicazione in un momento specifico, di solito quando l'applicazione si arresta in modo anomalo.

Sapere come gestire questi file può aiutarti a trovare le cause principali di un errore. Anche se non sei uno sviluppatore, i file di dump creati sul tuo sistema possono essere molto utili (oltre che accessibili) nella comprensione del software.

Questo è un articolo pratico e puoi seguire l'esempio clonando il repository dell'applicazione di esempio con:

git clone https://github.com/hANSIc99/core_dump_example.git

Come i segnali si relazionano ai dump

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

I segnali sono una sorta di comunicazione interprocesso tra il sistema operativo e le applicazioni utente. Linux utilizza i segnali definiti nello standard POSIX. Sul tuo sistema puoi trovare i segnali standard definiti in /usr/include/bits/signum-generic.h . C'è anche una pagina informativa del segnale man se vuoi di più sull'uso dei segnali nella tua applicazione. In parole povere, Linux utilizza i segnali per attivare ulteriori attività in base al fatto che fossero previste o impreviste.

Quando esci da un'applicazione in esecuzione, l'applicazione riceverà solitamente il SIGTERM segnale. Poiché è previsto questo tipo di segnale di uscita, questa azione non creerà un dump della memoria.

I seguenti segnali causeranno la creazione di un file dump (fonte:GNU C Library):

  • SIGFPE:operazione aritmetica errata
  • SIGILL:istruzioni illegali
  • SIGSEGV:accesso allo spazio di archiviazione non valido
  • SIGBUS:errore bus
  • SIGABRT:un errore rilevato dal programma e segnalato chiamando abort
  • SIGIOT:etichettato come arcaico su Fedora, questo segnale si attivava su abort() su un PDP-11 e ora mappa su SIGABRT

Creazione di file dump

Vai a core_dump_example directory, esegui make ed eseguire l'esempio con -c1 interruttore:

./coredump -c1

L'applicazione dovrebbe uscire nello stato 4 con un errore:

"Abgebrochen (Speicherabzug geschrieben)" si traduce approssimativamente in "Errore di segmentazione (core dumped)."

La creazione o meno di un core dump è determinata dal limite di risorse dell'utente che esegue il processo. Puoi modificare i limiti delle risorse con ulimit comando.

Controlla l'impostazione corrente per la creazione del dump principale:

ulimit -c

Se restituisce unlimited , quindi utilizza l'impostazione predefinita (consigliata). In caso contrario, correggi il limite con:

ulimit -c unlimited

Per disabilitare il tipo di creazione dei core dump:

ulimit -c 0

Il numero specifica la risorsa in kilobyte.

Cosa sono i core dump?

Il modo in cui il kernel gestisce i core dump è definito in:

/proc/sys/kernel/core_pattern

Sto eseguendo Fedora 31 e sul mio sistema il file contiene:

/usr/lib/systemd/systemd-coredump %P %u %g %s %t %c %h

Questo mostra che i core dump vengono inoltrati a systemd-coredump utilità. Il contenuto di core_pattern può variare ampiamente tra le diverse versioni delle distribuzioni Linux. Quando systemd-coredump è in uso, i file di dump vengono salvati compressi in /var/lib/systemd/coredump . Non è necessario toccare direttamente i file; invece, puoi usare coredumpctl . Ad esempio:

coredumpctl list

mostra tutti i file di dump disponibili salvati sul tuo sistema.

Con coredumpctl dump , puoi recuperare le informazioni dall'ultimo file di dump salvato:

[stephan@localhost core_dump_example]$ ./coredump 
Application started…

(…….)

Message: Process 4598 (coredump) of user 1000 dumped core.

Stack trace of thread 4598:
#0 0x00007f4bbaf22625 __GI_raise (libc.so.6)
#1 0x00007f4bbaf0b8d9 __GI_abort (libc.so.6)
#2 0x00007f4bbaf664af __libc_message (libc.so.6)
#3 0x00007f4bbaf6da9c malloc_printerr (libc.so.6)
#4 0x00007f4bbaf6f49c _int_free (libc.so.6)
#5 0x000000000040120e n/a (/home/stephan/Dokumente/core_dump_example/coredump)
#6 0x00000000004013b1 n/a (/home/stephan/Dokumente/core_dump_example/coredump)
#7 0x00007f4bbaf0d1a3 __libc_start_main (libc.so.6)
#8 0x000000000040113e n/a (/home/stephan/Dokumente/core_dump_example/coredump)
Refusing to dump core to tty (use shell redirection or specify — output).

Questo mostra che il processo è stato interrotto da SIGABRT . La traccia dello stack in questa visualizzazione non è molto dettagliata perché non include i nomi delle funzioni. Tuttavia, con coredumpctl debug , puoi semplicemente aprire il file dump con un debugger (GDB per impostazione predefinita). Digita bt (abbreviazione di backtrace) per ottenere una vista più dettagliata:

Core was generated by `./coredump -c1'.
Program terminated with signal SIGABRT, Aborted.
#0  __GI_raise (sig=sig@entry=6) at ../sysdeps/unix/sysv/linux/raise.c:50
50  return ret;
(gdb) bt
#0  __GI_raise (sig=sig@entry=6) at ../sysdeps/unix/sysv/linux/raise.c:50
#1  0x00007fc37a9aa8d9 in __GI_abort () at abort.c:79
#2  0x00007fc37aa054af in __libc_message (action=action@entry=do_abort, fmt=fmt@entry=0x7fc37ab14f4b "%s\n") at ../sysdeps/posix/libc_fatal.c:181
#3  0x00007fc37aa0ca9c in malloc_printerr (str=str@entry=0x7fc37ab130e0 "free(): invalid pointer") at malloc.c:5339
#4  0x00007fc37aa0e49c in _int_free (av=<optimized out>, p=<optimized out>, have_lock=0) at malloc.c:4173
#5  0x000000000040120e in freeSomething(void*) ()
#6  0x0000000000401401 in main ()

Gli indirizzi di memoria:main() e freeSomething() sono piuttosto bassi rispetto ai frame successivi. A causa del fatto che gli oggetti condivisi sono mappati su un'area alla fine dello spazio degli indirizzi virtuali, puoi presumere che il SIGABRT è stato causato da una chiamata in una libreria condivisa. Gli indirizzi di memoria degli oggetti condivisi non sono costanti tra le chiamate, quindi va benissimo quando vedi indirizzi variabili tra le chiamate.

La traccia dello stack mostra che le chiamate successive provengono da malloc.c , che indica che qualcosa con la (dis)allocazione della memoria potrebbe essere andato storto.

Nel codice sorgente, puoi vedere (anche senza alcuna conoscenza del C++) che ha cercato di liberare un puntatore, che non è stato restituito da una funzione di gestione della memoria. Ciò si traduce in un comportamento indefinito e causa il SIGABRT :

void freeSomething(void *ptr){
    free(ptr);
}
int nTmp = 5;
int *ptrNull = &nTmp;
freeSomething(ptrNull);

L'utilità systemd coredump può essere configurata in /etc/systemd/coredump.conf . La rotazione della pulizia dei file di dump può essere configurata in /etc/systemd/system/systemd-tmpfiles-clean.timer .

Puoi trovare maggiori informazioni su coredumpctl nella sua pagina man.

Compilazione con simboli di debug

Apri il Makefile e commenta l'ultima parte della riga 9. Ora dovrebbe assomigliare a:

CFLAGS =-Wall -Werror -std=c++11 -g

Il -g switch consente al compilatore di creare informazioni di debug. Avvia l'applicazione, questa volta con il -c2 interruttore:

./coredump -c2

Otterrai un'eccezione in virgola mobile. Apri il dump in GDB con:

coredumpctl debug

Questa volta, vieni indirizzato direttamente alla riga nel codice sorgente che ha causato l'errore:

Reading symbols from /home/stephan/Dokumente/core_dump_example/coredump…
[New LWP 6218]
Core was generated by `./coredump -c2'.
Program terminated with signal SIGFPE, Arithmetic exception.
#0 0x0000000000401233 in zeroDivide () at main.cpp:29
29 nRes = 5 / nDivider;
(gdb)

Digita list per avere una migliore panoramica del codice sorgente:

(gdb) list
24      int zeroDivide(){
25          int nDivider = 5;
26          int nRes = 0;
27          while(nDivider > 0){
28              nDivider--;
29              nRes = 5 / nDivider;
30          }
31          return nRes;
32      }

Usa il comando info locals per recuperare i valori delle variabili locali dal momento in cui l'applicazione non è riuscita:

(gdb) info locals
nDivider = 0
nRes = 5

In combinazione con il codice sorgente, puoi vedere che ti sei imbattuto in una divisione per zero:

nRes = 5 / 0

Conclusione

Sapere come gestire i file di dump ti aiuterà a trovare e correggere bug casuali difficili da riprodurre in un'applicazione. E se non è la tua applicazione, l'inoltro di un core dump allo sviluppatore lo aiuterà a trovare e risolvere il problema.


Linux
  1. Creazione, eliminazione e gestione di directory su Linux

  2. Trova i file e le directory più grandi in Linux

  3. Come estrarre i file .gz e .tar.gz in Linux

  4. Risoluzione dei problemi e debug della rete Linux?

  5. Linux:directory standard e/o comuni su OS Unix/linux?

Come comprimere file e directory in Linux

Pigz:comprimi e decomprimi file in parallelo in Linux

Come installare Rclone in Linux e Unix

Risparmia spazio comprimendo file e cartelle in Linux

Trova facilmente file e directory su Linux

Condivisione di file tra Linux Mint e Windows 10