Pergunta

Tenho um processo no Linux que está apresentando falha de segmentação.Como posso dizer para gerar um core dump quando ele falhar?

Foi útil?

Solução

Isso depende de qual shell você está usando.Se você estiver usando o bash, o comando ulimit controla várias configurações relacionadas à execução do programa, como se você deve despejar o núcleo.Se você digitar

ulimit -c unlimited

então isso dirá ao bash que seus programas podem despejar núcleos de qualquer tamanho.Você pode especificar um tamanho como 52M em vez de ilimitado, se desejar, mas na prática isso não deve ser necessário, pois o tamanho dos arquivos principais provavelmente nunca será um problema para você.

Em tcsh, você digitaria

limit coredumpsize unlimited

Outras dicas

Conforme explicado acima, a verdadeira questão colocada aqui é como habilitar core dumps em um sistema onde eles não estão habilitados.Essa pergunta é respondida aqui.

Se você veio aqui esperando aprender como gerar um core dump para um processo travado, a resposta é

gcore <pid>

se o gcore não estiver disponível no seu sistema, então

kill -ABRT <pid>

Não use kill -SEGV pois isso frequentemente invocará um manipulador de sinal, dificultando o diagnóstico do processo travado

O que fiz no final foi anexar o gdb ao processo antes que ele travasse e, quando ele obteve o segfault, executei o generate-core-file comando.Essa geração forçada de um core dump.

Para verificar onde os core dumps são gerados, execute:

sysctl kernel.core_pattern

ou:

cat /proc/sys/kernel/core_pattern

onde %e é o nome do processo e %t a hora do sistema.Você pode alterá-lo em /etc/sysctl.conf e recarregando por sysctl -p.

Se os arquivos principais não forem gerados (teste-os: sleep 10 & e killall -SIGSEGV sleep), verifique os limites por: ulimit -a.

Se o tamanho do seu arquivo principal for limitado, execute:

ulimit -c unlimited

para torná-lo ilimitado.

Em seguida, teste novamente, se o core dump for bem-sucedido, você verá “(core dumped)” após a indicação de falha de segmentação conforme abaixo:

Falha de segmentação:11 (núcleo descartado)

Veja também: core dumped - mas o arquivo core não está no diretório atual?


Ubuntu

No Ubuntu, os core dumps são tratados por Aportar e pode estar localizado em /var/crash/.No entanto, ele está desabilitado por padrão em versões estáveis.

Para mais detalhes, verifique: Onde encontro o core dump no Ubuntu?.

Mac OS

Para macOS, consulte: Como gerar core dumps no Mac OS X?

Talvez você pudesse fazer desta forma, este programa é uma demonstração de como interceptar uma falha de segmentação e enviar para um depurador (este é o código original usado em AIX) e imprime o rastreamento de pilha até o ponto de uma falha de segmentação.Você precisará alterar o sprintf variável a ser usada gdb no caso do 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 */
}

Você pode ter que adicionar adicionalmente um parâmetro para fazer com que o gdb despeje o núcleo, como mostrado aqui neste blog aqui.

Há mais coisas que podem influenciar a geração de um core dump.Eu encontrei estes:

  • o diretório do dump deve ser gravável.Por padrão, este é o diretório atual do processo, mas pode ser alterado configurando /proc/sys/kernel/core_pattern.
  • em algumas condições, o valor do kernel em /proc/sys/fs/suid_dumpable pode impedir que o núcleo seja gerado.

Existem mais situações que podem impedir a geração descritas na página de manual - tente man core.

Para ativar o dump principal, faça o seguinte:

  1. Em /etc/profile comente a linha:

    # ulimit -S -c 0 > /dev/null 2>&1
    
  2. Em /etc/security/limits.conf comente a linha:

    *               soft    core            0
    
  3. execute o cmd limit coredumpsize unlimited e verifique com 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. para verificar se o arquivo principal foi gravado, você pode encerrar o processo relacionado com cmd kill -s SEGV <PID> (não deve ser necessário, caso nenhum arquivo principal seja gravado, isso pode ser usado como verificação):

    # kill -s SEGV <PID>
    

Depois que o corefile for gravado, certifique-se de desativar as configurações do coredump novamente nos arquivos relacionados (1./2./3.)!

Para Ubuntu 14.04

  1. Verifique o core dump habilitado:

    ulimit -a
    
  2. Uma das linhas deve ser:

    core file size          (blocks, -c) unlimited
    
  3. Se não :

    gedit ~/.bashrc e adicione ulimit -c unlimited até o final do arquivo e salve, execute novamente o terminal.

  4. Crie seu aplicativo com informações de depuração:

    Em Makefile -O0 -g

  5. Execute o aplicativo que cria o core dump (o arquivo core dump com o nome ‘core’ deve ser criado próximo ao arquivo application_name):

    ./application_name
    
  6. Execute em gdb:

    gdb application_name core
    

Por padrão, você receberá um arquivo principal.Verifique se o diretório atual do processo é gravável ou nenhum arquivo principal será criado.

Melhor ativar o core dump programaticamente usando chamada do sistema setrlimit.

exemplo:

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

Espere.Isso acontece automaticamente.Não há necessidade de fazer isso

Vale ressaltar que se você tiver um sistema configurado, então as coisas são um pouco diferentes.A configuração normalmente teria os arquivos principais sendo canalizados, por meio de core_pattern valor sysctl, através systemd-coredump(8).O tamanho do arquivo principal rlimit normalmente já estaria configurado como "ilimitado".

É então possível recuperar os core dumps usando coredumpctl(1).

O armazenamento de core dumps, etc.é configurado por coredump.conf(5).Existem exemplos de como obter os arquivos principais na página de manual coredumpctl, mas, resumindo, ficaria assim:

Encontre o arquivo principal:

[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

Obtenha o arquivo principal:

[vps@phoenix]~$ coredumpctl -o test_me.core dump 16163
Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top