Eu tenho um processo no Linux que está recebendo uma falha de segmentação. Como posso dizer para gerar um dump principal quando falha?
Eu tenho um processo no Linux que está recebendo uma falha de segmentação. Como posso dizer para gerar um dump principal quando falha?
Respostas:
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
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
-ABRT
invoque 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
.
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 %t
a hora do sistema. Você pode alterá-lo /etc/sysctl.conf
e 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?
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? .
Para o macOS, consulte: Como gerar dumps principais no Mac OS X?
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-file
comando. Essa geração forçada de um core dump.
ge
)
ulimit -c
como unlimited
, mas o arquivo principal ainda não foi criado, o generate-core-file
arquivo na sessão gdb cria o arquivo principal, obrigado.
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 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 */
}
Pode ser necessário adicionar um parâmetro adicional para 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:
/proc/sys/kernel/core_pattern
. /proc/sys/fs/suid_dumpable
pode 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
.
Para ativar o dump principal, faça o seguinte:
Em /etc/profile
comentar a linha:
# ulimit -S -c 0 > /dev/null 2>&1
No /etc/security/limits.conf
comentário da linha:
* soft core 0
execute o cmd limit coredumpsize unlimited
e 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
#
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.)!
Para o Ubuntu 14.04
Verifique o dump principal ativado:
ulimit -a
Uma das linhas deve ser:
core file size (blocks, -c) unlimited
Se não :
gedit ~/.bashrc
adicione ulimit -c unlimited
no 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 sob gdb:
gdb application_name core
ulimit -c unlimited
no terminal para uma solução temporária, porque apenas a edição ~/.bashrc
requer reinicialização do terminal para que as alterações tenham efeito.
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.
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));
}
ulimit -c unlimited
no ambiente da linha de comando e execute novamente o aplicativo.
ulimit -c unlimited
. Além disso, você pode compilar com a definição de marco, o aplicativo não incluirá enable_core_dump
sí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.
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_pattern
valor 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
Ubuntu 19.04
Todas as outras respostas em si não me ajudaram. Mas a seguinte soma fez o trabalho
Crie ~/.config/apport/settings
com 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:
core_pattern
. Esteja ciente de que esse arquivo pode ser substituído pelo serviço apport ao reiniciar.ulimit -c
valor 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: