Come generare un dump principale in Linux su un errore di segmentazione?


Risposte:


249

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

21
@lzprgmr: Per chiarire: il motivo per cui i dump core non vengono generati per impostazione predefinita è che il limite non è impostato e / o impostato su 0, il che impedisce il dump del core. Impostando un limite illimitato, garantiamo che i dump core possano sempre essere generati.
Eli Courtwright,

6
Questo collegamento approfondisce e offre alcune opzioni in più per consentire la generazione di core dump in Linux. L'unico inconveniente è che alcuni comandi / impostazioni non vengono spiegati.
Salsa,

6
Su bash 4.1.2 (1) non è possibile specificare limiti di rilascio come 52M, con conseguente messaggio di errore numerico non valido. La pagina man dice che "I valori sono in incrementi di 1024 byte".
a1

4
Bene, ho avuto un "piccolo" progetto OpenGL, che una volta ha fatto qualcosa di strano e ha causato l'arresto anomalo del server X. Quando sono tornato, ho visto un piccolo file core da 17 GB (su una partizione da 25 GB). È sicuramente una buona idea limitare le dimensioni del file core :)
IceCool

1
@PolarisUser: Se vuoi assicurarti che la tua partizione non venga mangiata, ti consiglio di impostare un limite di qualcosa come 1 concerto. Dovrebbe essere abbastanza grande da gestire qualsiasi ragionevole core dump, senza minacciare di utilizzare tutto lo spazio rimanente sul disco rigido.
Eli Courtwright,

60

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


Penso che sia molto più probabile che -ABRTinvochi 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.
celticminstrel,

32

Per verificare dove vengono generati i core dump, eseguire:

sysctl kernel.core_pattern

o:

cat /proc/sys/kernel/core_pattern

dove %esono il nome del processo e %tl'ora del sistema. Puoi cambiarlo /etc/sysctl.confe 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?


Ubuntu

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?.

Mac OS

Per macOS, vedi: Come generare core dump in Mac OS X?


3
Per Ubuntu, per tornare rapidamente al normale comportamento (scaricando un file core nella directory corrente), è sufficiente interrompere il servizio apport con "sudo service apport stop". Si noti inoltre che se si esegue all'interno della finestra mobile, tale impostazione è controllata sul sistema host e non all'interno del contenitore.
Digicrat,

26

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-filecomando. Quella generazione forzata di una discarica principale.


Come hai collegato gdb al processo?
Chani,

6
Per rispondere a Ritwik G, per allegare un processo a gdb, basta avviare gdb e inserire 'attach <pid>' dove <pid> è il numero pid del processo che si desidera collegare.
Jean-Dominique Frattini,

(abbreviato come ge)
user202729

Se hanno una nuova domanda, dovrebbero porre una nuova domanda invece di porre un commento.
user202729

Cosa strana è già impostato ulimit -ca unlimited, ma il file core non è placato creato, il generate-core-filefile nella sessione di gdb fa creare il file core, grazie.
CodyChan,

19

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 sprintfvariabile da usare gdbnel 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 .


16

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_dumpablepotrebbe impedire la generazione del core.

Ci sono altre situazioni che possono impedire la generazione descritta nella pagina man - prova man core.


9

Per attivare il dump del core, procedere come segue:

  1. Nel /etc/profilecommento la linea:

    # ulimit -S -c 0 > /dev/null 2>&1
  2. Nel /etc/security/limits.confcommento fuori linea:

    *               soft    core            0
  3. esegui il cmd limit coredumpsize unlimitede 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
    #
  4. 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.)!


9

Per Ubuntu 14.04

  1. Verifica core dump abilitato:

    ulimit -a
  2. Una delle linee dovrebbe essere:

    core file size          (blocks, -c) unlimited
  3. Altrimenti :

    gedit ~/.bashrce aggiungere ulimit -c unlimitedalla fine del file e salvare, rieseguire il terminale.

  4. Crea la tua applicazione con le informazioni di debug:

    In Makefile -O0 -g

  5. Esegui applicazione che crea core dump (il file core dump con nome 'core' dovrebbe essere creato vicino al file application_name):

    ./application_name
  6. Esegui con gdb:

    gdb application_name core

Nel passaggio 3, come "rieseguire" il terminale? Intendi riavviare?
Naveen,

@Naveen no, basta chiudere il terminale e aprirne uno nuovo, inoltre sembra che tu possa semplicemente inserire il ulimit -c unlimitedterminale per una soluzione temporanea, perché solo la modifica ~/.bashrcrichiede la riavvio del terminale per rendere effettive le modifiche.
MrGloom,

4

Di default otterrai un file core. Verificare che la directory corrente del processo sia scrivibile o che non verrà creato alcun file core.


4
Per "directory corrente del processo" intendi $ cwd al momento dell'esecuzione del processo? ~ / abc> / usr / bin / cat def se cat si blocca, la directory corrente è in questione ~ / abc o / usr / bin?
Nathan Fellman,

5
~ / abc. Hmm, i commenti devono essere lunghi 15 caratteri!
Mark Harrison,

5
Questa sarebbe la directory corrente al momento del SEGV. Inoltre, i processi in esecuzione con un utente e / o un gruppo effettivi diversi rispetto al vero utente / gruppo non scriveranno i file core.
Darron,

2

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));
}

perché è meglio?
Nathan Fellman,

file core generato dopo l'arresto anomalo, non è necessario ulimit -c unlimitednell'ambiente della riga di comando, quindi rieseguire l'applicazione.
kgbook,

Non voglio un core dump ogni volta che si blocca, solo quando un utente mi contatta come sviluppatore per guardarlo. Se si blocca 100 volte, non ho bisogno di 100 core dump da guardare.
Nathan Fellman,

In tal caso, meglio usare ulimit -c unlimited. Inoltre puoi compilare con la definizione di marco, l'applicazione non includerà il enable_core_dumpsimbolo se non definisci quella macro al momento del rilascio e otterrai un dump principale sostituendolo con la versione di debug.
kgbook,

anche se è qualificato da una macro, ciò mi richiede comunque di ricompilare se voglio generare un core dump, piuttosto che semplicemente eseguire un comando nella shell prima di eseguire nuovamente.
Nathan Fellman,

1

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_patternvalore 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

0

Ubuntu 19.04

Tutte le altre risposte stesse non mi hanno aiutato. Ma il seguente riassunto ha fatto il lavoro

Crea ~/.config/apport/settingscon 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:

  • Alcune risposte suggeriscono di cambiare core_pattern . Tenere presente che il file potrebbe essere sovrascritto dal servizio apport al riavvio.
  • La semplice interruzione di apport non ha fatto il lavoro
  • Il ulimit -cvalore potrebbe essere modificato automaticamente mentre stai provando altre risposte sul Web. Assicurati di controllarlo regolarmente durante l'impostazione della creazione del dump principale.

Riferimenti:

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.