Como gerar um dump principal no Linux em uma falha de segmentação?

217

Eu tenho um processo no Linux que está recebendo uma falha de segmentação. Como posso dizer para gerar um dump principal quando falha?

Nathan Fellman
fonte
1
Como para o visualizar aftewards: stackoverflow.com/questions/8305866/...
Ciro Santilli郝海东冠状病六四事件法轮功

Respostas:

249

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

isso informará 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ê.

No tcsh, você digitaria

limit coredumpsize unlimited
Eli Courtwright
fonte
21
@lzprgmr: Para esclarecer: a razão pela qual os dumps do núcleo não são gerados por padrão é que o limite não está definido e / ou definido como 0, o que impede que o núcleo seja descartado. Ao definir um limite ilimitado, garantimos que os dumps principais sempre possam ser gerados.
Eli Courtwright
6
Esse link é mais profundo e oferece mais algumas opções para permitir a geração de core dumps no linux. A única desvantagem é que alguns comandos / configurações são deixados sem explicação.
Salsa
6
No bash 4.1.2 (1), limites de liberação como 52M não podem ser especificados, resultando em uma mensagem de erro de número inválido. A página do manual informa que "Os valores estão em incrementos de 1024 bytes".
a1an
4
Bem, eu tive um projeto "pequeno" do OpenGL, que uma vez fez alguma coisa estranha e causou uma falha no servidor X. Quando efetuei o logon, vi um pequeno arquivo principal de 17 GB (em uma partição de 25 GB). É definitivamente uma boa idéia para manter o tamanho do arquivo núcleo limitado :)
IceCool
1
@PolarisUser: Se você quiser garantir que sua partição não seja consumida, recomendo definir um limite de algo como 1 gig. Isso deve ser grande o suficiente para lidar com qualquer despejo de núcleo razoável, sem ameaçar usar todo o espaço restante no disco rígido.
Eli Courtwright
60

Conforme explicado acima, a verdadeira pergunta que está sendo feita aqui é como habilitar os dumps principais em um sistema em que eles não estão habilitados. Essa pergunta é respondida aqui.

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

gcore <pid>

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

kill -ABRT <pid>

Não use kill -SEGV, pois isso geralmente chama um manipulador de sinais, dificultando o diagnóstico do processo bloqueado

George Co
fonte
Eu acho que é muito mais provável que -ABRTinvoque um manipulador de sinal do que -SEGV, pois um abort é mais provável que seja recuperável do que um segfault. (Se você manipular um segfault, normalmente ele será acionado novamente assim que o manipulador sair.) Uma melhor opção de sinal para gerar um dump principal é -QUIT.
celticminstrel 25/02
32

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

sysctl kernel.core_pattern

ou:

cat /proc/sys/kernel/core_pattern

onde %eé o nome do processo e %ta hora do sistema. Você pode alterá-lo /etc/sysctl.confe recarregá-lo sysctl -p.

Se os arquivos principais não são gerados (testá-lo: sleep 10 &e killall -SIGSEGV sleep), verificar 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 dumping no núcleo for bem-sucedido, você verá "(core dumped)" após a indicação de falha de segmentação, conforme abaixo:

Falha na segmentação: 11 (núcleo despejado)

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


Ubuntu

No Ubuntu, os core dumps são gerenciados pelo Apport e podem ser localizados em /var/crash/. No entanto, é desativado por padrão em versões estáveis.

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

Mac OS

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

kenorb
fonte
3
Para o Ubuntu, para retornar rapidamente ao comportamento normal (despejar um arquivo principal no diretório atual), basta parar o serviço apport com "sudo service apport stop". Observe também que, se você estiver executando na janela de encaixe, essa configuração será controlada no sistema host e não no contêiner.
Digicrat
26

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

Nathan Fellman
fonte
Como você anexou o gdb ao processo?
Chani
6
Para responder ao Ritwik G, para anexar um processo ao gdb, basta iniciar o gdb e digite 'attach <pid>' onde <pid> é o número do pid do processo que você deseja anexar.
Jean-Dominique Frattini
(abreviado como ge)
user202729
Se eles tiverem uma nova pergunta, devem fazer uma nova pergunta em vez de fazer um comentário.
user202729
O estranho é que eu já defini ulimit -ccomo unlimited, mas o arquivo principal ainda não foi criado, o generate-core-filearquivo na sessão gdb cria o arquivo principal, obrigado.
CodyChan
19

Talvez você possa fazê-lo dessa maneira, este programa é uma demonstração de como capturar uma falha de segmentação e realizar a conversão para um depurador (este é o código original usado abaixo AIX) e imprimir o rastreamento da pilha até o ponto de uma falha de segmentação. Você precisará alterar a sprintfvariável a ser usada gdbno 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 */
}

Pode ser necessário adicionar um parâmetro adicional para que o gdb despeje o núcleo, como mostrado aqui neste blog aqui .

t0mm13b
fonte
16

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

  • o diretório para o dump deve ser gravável. Por padrão, este é o diretório atual do processo, mas isso pode ser alterado pela configuração /proc/sys/kernel/core_pattern.
  • em algumas condições, o valor do kernel em /proc/sys/fs/suid_dumpablepode impedir a geração do núcleo.

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

mlutescu
fonte
9

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

  1. Em /etc/profilecomentar a linha:

    # ulimit -S -c 0 > /dev/null 2>&1
  2. No /etc/security/limits.confcomentário da linha:

    *               soft    core            0
  3. execute o cmd limit coredumpsize unlimitede verifique-o com o 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 é gravado, você pode interromper o processo de relacionamento com o cmd kill -s SEGV <PID>(não deve ser necessário, caso não seja gravado nenhum arquivo principal, isso pode ser usado como verificação):

    # kill -s SEGV <PID>

Após a gravação do corefile, desative as configurações do coredump novamente nos arquivos relacionados (1./2./3.)!

Edgar Jordi
fonte
9

Para o Ubuntu 14.04

  1. Verifique o dump principal ativado:

    ulimit -a
  2. Uma das linhas deve ser:

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

    gedit ~/.bashrcadicione ulimit -c unlimitedno 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 sob gdb:

    gdb application_name core
Mrgloom
fonte
Na etapa 3, como 'reexecutar' o terminal? Você quer dizer reiniciar?
Naveen
@ Naveen não, basta fechar o terminal e abrir um novo, também parece que você pode simplesmente colocar ulimit -c unlimitedno terminal para uma solução temporária, porque apenas a edição ~/.bashrcrequer reinicialização do terminal para que as alterações tenham efeito.
mrgloom
4

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

Mark Harrison
fonte
4
Por "diretório atual do processo", você quer dizer $ cwd no momento em que o processo foi executado? ~ / abc> / usr / bin / cat def se o gato travar, o diretório atual está em questão ~ / abc ou / usr / bin?
18719 Nathan Fellman
5
~ / abc. Hmm, os comentários devem ter 15 caracteres!
Mark Harrison
5
Esse seria o diretório atual no momento do SEGV. Além disso, os processos em execução com um usuário e / ou grupo efetivo diferente do usuário / grupo real não gravam arquivos principais.
Darron
2

Melhor ativar o core dump programaticamente usando a 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));
}
kgbook
fonte
por que isso é melhor?
22618 Nathan Fellman
arquivo principal gerado após a falha, não é necessário ulimit -c unlimitedno ambiente da linha de comando e execute novamente o aplicativo.
precisa saber é o seguinte
Eu não quero um despejo central toda vez que ele falha, apenas quando um usuário entra em contato comigo como desenvolvedor para analisá-lo. Se ele travar 100 vezes, não preciso de 100 dumps principais para analisar.
Nathan Fellman
Nesse caso, melhor usar ulimit -c unlimited. Além disso, você pode compilar com a definição de marco, o aplicativo não incluirá enable_core_dumpsímbolo, se não definir essa macro quando for lançado, e você receberá um dump principal para substituir a versão de depuração.
precisa saber é o seguinte
mesmo que seja qualificado por uma macro, isso ainda exige que eu recompile se quiser gerar um core dump, em vez de simplesmente executar um comando no shell antes de executar novamente.
18719 Nathan Fellman
1

Vale ressaltar que, se você tem um sistema configurado, as coisas são um pouco diferentes. A configuração normalmente faria com que os arquivos principais fossem canalizados por meio do core_patternvalor sysctl systemd-coredump(8). O tamanho do arquivo principal rlimit normalmente já está configurado como "ilimitado".

É então possível recuperar os dumps do núcleo 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 do 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
Pawel Veselov
fonte
0

Ubuntu 19.04

Todas as outras respostas em si não me ajudaram. Mas a seguinte soma fez o trabalho

Crie ~/.config/apport/settingscom o seguinte conteúdo:

[main]
unpackaged=true

(Isso indica ao apport para também escrever dumps principais para aplicativos personalizados)

verificar: ulimit -c. Se der 0, corrija-o com

ulimit -c unlimited

Apenas no caso de reiniciar o apport:

sudo systemctl restart apport

Os arquivos de falha agora estão gravados /var/crash/. Mas você não pode usá-los com gdb. Para usá-los com gdb, use

apport-unpack <location_of_report> <target_directory>

Outras informações:

  • Algumas respostas sugerem mudanças core_pattern. Esteja ciente de que esse arquivo pode ser substituído pelo serviço apport ao reiniciar.
  • Simplesmente parar o apport não fez o trabalho
  • O ulimit -cvalor pode ser alterado automaticamente enquanto você tenta outras respostas da web. Verifique-o regularmente durante a configuração da criação do dump principal.

Referências:

DarkTrick
fonte