Como gerar um core dump no Linux em uma falha de segmentação?
Pergunta
Tenho um processo no Linux que está apresentando falha de segmentação.Como posso dizer para gerar um core dump quando ele falhar?
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:
Em
/etc/profile
comente a linha:# ulimit -S -c 0 > /dev/null 2>&1
Em
/etc/security/limits.conf
comente a linha:* soft core 0
execute o cmd
limit coredumpsize unlimited
e verifique com cmdlimit
:# 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 #
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
Verifique o core dump habilitado:
ulimit -a
Uma das linhas deve ser:
core file size (blocks, -c) unlimited
Se não :
gedit ~/.bashrc
e adicioneulimit -c unlimited
até o final do arquivo e salve, execute novamente o terminal.Crie seu aplicativo com informações de depuração:
Em Makefile
-O0 -g
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
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