Domanda

Ho un processo in Linux che riscontra un errore di segmentazione.Come posso dirgli di generare un core dump quando fallisce?

È stato utile?

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:

  1. In /etc/profile commenta la riga:

    # ulimit -S -c 0 > /dev/null 2>&1
    
  2. In /etc/security/limits.conf commentare la riga:

    *               soft    core            0
    
  3. 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
    #
    
  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 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

  1. Verifica core dump abilitato:

    ulimit -a
    
  2. Una delle righe dovrebbe essere:

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

    gedit ~/.bashrc e aggiungi ulimit -c unlimited alla fine del file e salva, riesegui il terminale.

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

    Nel Makefile -O0 -g

  5. 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
    
  6. 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
Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top