Come generare un core dump in Linux su un errore di segmentazione?
Domanda
Ho un processo in Linux che riscontra un errore di segmentazione.Come posso dirgli di generare un core dump quando fallisce?
Soluzione
Dipende da quale shell stai utilizzando.Se stai usando bash, il comando ulimit controlla diverse impostazioni relative all'esecuzione del programma, ad esempio se devi eseguire il dump del core.Se digiti
ulimit -c unlimited
quindi questo dirà a bash che i suoi programmi possono eseguire il dump di core di qualsiasi dimensione.Puoi specificare una dimensione come 52M invece che illimitata se lo desideri, ma in pratica questo non dovrebbe essere necessario poiché la dimensione dei file principali probabilmente non sarà mai un problema per te.
In tcsh, scriveresti
limit coredumpsize unlimited
Altri suggerimenti
Come spiegato sopra, la vera domanda che viene posta qui è come abilitare i core dump su un sistema in cui non sono abilitati.A questa domanda viene data risposta qui.
Se sei venuto qui sperando di imparare come generare un core dump per un processo bloccato, la risposta è
gcore <pid>
se gcore non è disponibile sul tuo sistema, allora
kill -ABRT <pid>
Non utilizzare kill -SEGV poiché ciò invocherà spesso un gestore di segnale rendendo più difficile la diagnosi del processo bloccato
Ciò che ho fatto alla fine è stato allegare gdb al processo prima che si bloccasse, e poi quando ha ricevuto il segfault ho eseguito il comando generate-core-file
comando.Quella generazione forzata di un core dump.
Per verificare dove vengono generati i core dump, eseguire:
sysctl kernel.core_pattern
O:
cat /proc/sys/kernel/core_pattern
Dove %e
è il nome del processo e %t
l'ora del sistema.Puoi cambiarlo /etc/sysctl.conf
e ricarica entro sysctl -p
.
Se i file core non vengono generati (testarlo con: sleep 10 &
E killall -SIGSEGV sleep
), verificare i limiti tramite: ulimit -a
.
Se la dimensione del file principale è limitata, esegui:
ulimit -c unlimited
per renderlo illimitato.
Quindi testare nuovamente, se il core dumping ha esito positivo, verrà visualizzato "(core dumped)" dopo l'indicazione dell'errore di segmentazione come di seguito:
Errore di segmentazione:11 (core dump)
Guarda anche: core scaricato - ma il file core non si trova nella directory corrente?
Ubuntu
In Ubuntu i core dump sono gestiti da Apporto e può essere situato in /var/crash/
.Tuttavia, è disabilitato per impostazione predefinita nelle versioni stabili.
Per maggiori dettagli, consultare: Dove trovo il core dump in Ubuntu?.
Mac OS
Per macOS, vedere: Come generare core dump in Mac OS X?
Forse potresti farlo in questo modo, questo programma è una dimostrazione di come intercettare un errore di segmentazione e inviarlo a un debugger (questo è il codice originale usato sotto AIX
) e stampa l'analisi dello stack fino al punto in cui si verifica un errore di segmentazione.Sarà necessario modificare il file sprintf
variabile da utilizzare gdb
nel caso di Linux.
#include <stdio.h>
#include <signal.h>
#include <stdlib.h>
#include <stdarg.h>
static void signal_handler(int);
static void dumpstack(void);
static void cleanup(void);
void init_signals(void);
void panic(const char *, ...);
struct sigaction sigact;
char *progname;
int main(int argc, char **argv) {
char *s;
progname = *(argv);
atexit(cleanup);
init_signals();
printf("About to seg fault by assigning zero to *s\n");
*s = 0;
sigemptyset(&sigact.sa_mask);
return 0;
}
void init_signals(void) {
sigact.sa_handler = signal_handler;
sigemptyset(&sigact.sa_mask);
sigact.sa_flags = 0;
sigaction(SIGINT, &sigact, (struct sigaction *)NULL);
sigaddset(&sigact.sa_mask, SIGSEGV);
sigaction(SIGSEGV, &sigact, (struct sigaction *)NULL);
sigaddset(&sigact.sa_mask, SIGBUS);
sigaction(SIGBUS, &sigact, (struct sigaction *)NULL);
sigaddset(&sigact.sa_mask, SIGQUIT);
sigaction(SIGQUIT, &sigact, (struct sigaction *)NULL);
sigaddset(&sigact.sa_mask, SIGHUP);
sigaction(SIGHUP, &sigact, (struct sigaction *)NULL);
sigaddset(&sigact.sa_mask, SIGKILL);
sigaction(SIGKILL, &sigact, (struct sigaction *)NULL);
}
static void signal_handler(int sig) {
if (sig == SIGHUP) panic("FATAL: Program hanged up\n");
if (sig == SIGSEGV || sig == SIGBUS){
dumpstack();
panic("FATAL: %s Fault. Logged StackTrace\n", (sig == SIGSEGV) ? "Segmentation" : ((sig == SIGBUS) ? "Bus" : "Unknown"));
}
if (sig == SIGQUIT) panic("QUIT signal ended program\n");
if (sig == SIGKILL) panic("KILL signal ended program\n");
if (sig == SIGINT) ;
}
void panic(const char *fmt, ...) {
char buf[50];
va_list argptr;
va_start(argptr, fmt);
vsprintf(buf, fmt, argptr);
va_end(argptr);
fprintf(stderr, buf);
exit(-1);
}
static void dumpstack(void) {
/* Got this routine from http://www.whitefang.com/unix/faq_toc.html
** Section 6.5. Modified to redirect to file to prevent clutter
*/
/* This needs to be changed... */
char dbx[160];
sprintf(dbx, "echo 'where\ndetach' | dbx -a %d > %s.dump", getpid(), progname);
/* Change the dbx to gdb */
system(dbx);
return;
}
void cleanup(void) {
sigemptyset(&sigact.sa_mask);
/* Do any cleaning up chores here */
}
Potrebbe essere necessario aggiungere inoltre un parametro per fare in modo che gdb esegua il dump del core come mostrato qui in questo blog Qui.
Ci sono più cose che possono influenzare la generazione di un core dump.Ho incontrato questi:
- la directory per il dump deve essere scrivibile.Per impostazione predefinita questa è la directory corrente del processo, ma può essere modificata impostando
/proc/sys/kernel/core_pattern
. - in alcune condizioni, il valore del kernel in
/proc/sys/fs/suid_dumpable
potrebbe impedire la generazione del nucleo.
Ci sono più situazioni che potrebbero impedire la generazione descritte nella pagina man: prova man core
.
Per attivare il core dump procedere come segue:
In
/etc/profile
commenta la riga:# ulimit -S -c 0 > /dev/null 2>&1
In
/etc/security/limits.conf
commentare la riga:* soft core 0
esegui il cmd
limit coredumpsize unlimited
e controllalo con cmdlimit
:# limit coredumpsize unlimited # limit cputime unlimited filesize unlimited datasize unlimited stacksize 10240 kbytes coredumpsize unlimited memoryuse unlimited vmemoryuse unlimited descriptors 1024 memorylocked 32 kbytes maxproc 528383 #
per verificare se il corefile viene scritto puoi terminare il processo relativo con cmd
kill -s SEGV <PID>
(non dovrebbe essere necessario, nel caso in cui non venga scritto alcun file core, questo può essere utilizzato come controllo):# kill -s SEGV <PID>
Una volta scritto il corefile assicurarsi di disattivare nuovamente le impostazioni coredump nei relativi file (1./2./3.) !
Per Ubuntu 14.04
Verifica core dump abilitato:
ulimit -a
Una delle righe dovrebbe essere:
core file size (blocks, -c) unlimited
Altrimenti :
gedit ~/.bashrc
e aggiungiulimit -c unlimited
alla fine del file e salva, riesegui il terminale.Crea la tua applicazione con le informazioni di debug:
Nel Makefile
-O0 -g
Esegui l'applicazione che crea il core dump (il file core dump con il nome "core" deve essere creato vicino al file application_name):
./application_name
Esegui sotto gdb:
gdb application_name core
Per impostazione predefinita otterrai un file core.Verificare che la directory corrente del processo sia scrivibile, altrimenti non verrà creato alcun file core.
È meglio attivare il core dump a livello di codice utilizzando la chiamata di sistema setrlimit
.
esempio:
#include <sys/resource.h>
bool enable_core_dump(){
struct rlimit corelim;
corelim.rlim_cur = RLIM_INFINITY;
corelim.rlim_max = RLIM_INFINITY;
return (0 == setrlimit(RLIMIT_CORE, &corelim));
}
Aspettare.Lo fa automaticamente.Non c'è bisogno di farlo
Vale la pena ricordare che se hai a systemd impostato, le cose sono leggermente diverse.La configurazione in genere prevede il reindirizzamento dei file principali, tramite core_pattern
valore sysctl, attraverso systemd-coredump(8)
.Il limite della dimensione del file principale in genere è già configurato come "illimitato".
È quindi possibile recuperare i core dump utilizzando coredumpctl(1)
.
Lo stoccaggio di core dump, ecc.è configurato da coredump.conf(5)
.Ci sono esempi di come ottenere i file core nella pagina man coredumpctl, ma in breve sarebbe simile a questo:
Trova il file principale:
[vps@phoenix]~$ coredumpctl list test_me | tail -1
Sun 2019-01-20 11:17:33 CET 16163 1224 1224 11 present /home/vps/test_me
Ottieni il file principale:
[vps@phoenix]~$ coredumpctl -o test_me.core dump 16163