Ho un processo in Linux che sta ottenendo un errore di segmentazione. Come posso dirgli di generare un dump principale quando fallisce?
Ho un processo in Linux che sta ottenendo un errore di segmentazione. Come posso dirgli di generare un dump principale quando fallisce?
Risposte:
Questo dipende dalla shell che stai usando. Se si utilizza bash, il comando ulimit controlla diverse impostazioni relative all'esecuzione del programma, ad esempio se è necessario eseguire il dump del core. Se digiti
ulimit -c unlimited
allora ciò dirà a bash che i suoi programmi possono scaricare core di qualsiasi dimensione. Se lo desideri, puoi specificare una dimensione come 52M anziché illimitata, ma in pratica ciò non dovrebbe essere necessario poiché la dimensione dei file core probabilmente non sarà mai un problema per te.
In tcsh, dovresti digitare
limit coredumpsize unlimited
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 dump principale per un processo bloccato, la risposta è
gcore <pid>
se gcore non è disponibile sul tuo sistema, allora
kill -ABRT <pid>
Non usare kill -SEGV poiché ciò invocherà spesso un gestore di segnali che rende più difficile la diagnosi del processo bloccato
-ABRT
invochi un gestore del segnale che -SEGV
, poiché è più probabile che un abort sia recuperabile di un segfault. (Se gestisci un segfault, normalmente si innescherà di nuovo non appena il gestore uscirà.) È una scelta migliore del segnale per generare un core dump -QUIT
.
Per verificare dove vengono generati i core dump, eseguire:
sysctl kernel.core_pattern
o:
cat /proc/sys/kernel/core_pattern
dove %e
sono il nome del processo e %t
l'ora del sistema. Puoi cambiarlo /etc/sysctl.conf
e ricaricarlosysctl -p
.
Se i file core non vengono generati (provalo con: sleep 10 &
e killall -SIGSEGV sleep
), controlla i limiti con:ulimit -a
.
Se la dimensione del tuo file core è limitata, esegui:
ulimit -c unlimited
per renderlo illimitato.
Quindi riprovare, se lo scarico del core ha esito positivo, dopo l'indicazione dell'errore di segmentazione verrà visualizzato "(core dumped)":
Errore di segmentazione: 11 (core scaricato)
Vedi anche: core scaricato - ma il file core non è nella directory corrente?
In Ubuntu i dump principali sono gestiti da Apport e possono essere localizzati/var/crash/
. Tuttavia, è disabilitato per impostazione predefinita nelle versioni stabili.
Per maggiori dettagli, controlla: Dove trovo il dump principale in Ubuntu?.
Per macOS, vedi: Come generare core dump in Mac OS X?
Quello che ho fatto alla fine è stato collegare gdb al processo prima che si arrestasse in modo anomalo, quindi quando ha ottenuto il segfault ho eseguito il generate-core-file
comando. Quella generazione forzata di una discarica principale.
ge
)
ulimit -c
a unlimited
, ma il file core non è placato creato, il generate-core-file
file nella sessione di gdb fa creare il file core, grazie.
Forse potresti farlo in questo modo, questo programma è una dimostrazione di come intercettare un errore di segmentazione e esegue il shell su un debugger (questo è il codice originale usato sotto AIX
) e stampa la traccia dello stack fino al punto di un errore di segmentazione. Dovrai cambiare la sprintf
variabile da usare 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 un parametro per far sì 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:
/proc/sys/kernel/core_pattern
. /proc/sys/fs/suid_dumpable
potrebbe impedire la generazione del core.Ci sono altre situazioni che possono impedire la generazione descritta nella pagina man - prova man core
.
Per attivare il dump del core, procedere come segue:
Nel /etc/profile
commento la linea:
# ulimit -S -c 0 > /dev/null 2>&1
Nel /etc/security/limits.conf
commento fuori linea:
* soft core 0
esegui il cmd limit coredumpsize unlimited
e controllalo con cmd limit
:
# 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 usato come un controllo):
# kill -s SEGV <PID>
Una volta che il corefile è stato scritto assicurati di disattivare nuovamente le impostazioni di coredump nei relativi file (1./2./3.)!
Per Ubuntu 14.04
Verifica core dump abilitato:
ulimit -a
Una delle linee dovrebbe essere:
core file size (blocks, -c) unlimited
Altrimenti :
gedit ~/.bashrc
e aggiungere ulimit -c unlimited
alla fine del file e salvare, rieseguire il terminale.
Crea la tua applicazione con le informazioni di debug:
In Makefile -O0 -g
Esegui applicazione che crea core dump (il file core dump con nome 'core' dovrebbe essere creato vicino al file application_name):
./application_name
Esegui con gdb:
gdb application_name core
ulimit -c unlimited
terminale per una soluzione temporanea, perché solo la modifica ~/.bashrc
richiede la riavvio del terminale per rendere effettive le modifiche.
Di default otterrai un file core. Verificare che la directory corrente del processo sia scrivibile o che non verrà creato alcun file core.
Meglio attivare il dump del core a livello di codice usando 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));
}
ulimit -c unlimited
nell'ambiente della riga di comando, quindi rieseguire l'applicazione.
ulimit -c unlimited
. Inoltre puoi compilare con la definizione di marco, l'applicazione non includerà il enable_core_dump
simbolo se non definisci quella macro al momento del rilascio e otterrai un dump principale sostituendolo con la versione di debug.
Vale la pena di ricordare che, se si dispone di un systemd set up, poi le cose sono un po 'diverso. L'installazione in genere prevede il piping dei file core, mediante il core_pattern
valore sysctl, tramite systemd-coredump(8)
. La dimensione del file core rlimit in genere sarebbe già configurata come "illimitata".
È quindi possibile recuperare i dump principali mediante coredumpctl(1)
.
La memorizzazione dei core dump, ecc. È configurata da coredump.conf(5)
. Ci sono esempi di come ottenere i file core nella pagina man di coredumpctl, ma in breve sembrerebbe così:
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
Ubuntu 19.04
Tutte le altre risposte stesse non mi hanno aiutato. Ma il seguente riassunto ha fatto il lavoro
Crea ~/.config/apport/settings
con il seguente contenuto:
[main]
unpackaged=true
(Questo dice a apport di scrivere anche core dump per app personalizzate)
controllare: ulimit -c
. Se genera 0, correggilo con
ulimit -c unlimited
Solo per in caso di riavvio apport:
sudo systemctl restart apport
I file di crash sono ora scritti in /var/crash/
. Ma non puoi usarli con gdb. Per usarli con gdb, usa
apport-unpack <location_of_report> <target_directory>
Ulteriori informazioni:
core_pattern
. Tenere presente che il file potrebbe essere sovrascritto dal servizio apport al riavvio.ulimit -c
valore potrebbe essere modificato automaticamente mentre stai provando altre risposte sul Web. Assicurati di controllarlo regolarmente durante l'impostazione della creazione del dump principale.Riferimenti: