Como causar um dump principal em C / C ++ de maneira programática


93

Eu gostaria de forçar um despejo de memória em um local específico em meu aplicativo C ++.

Eu sei que posso fazer isso fazendo algo como:

int * crash = NULL;
*crash = 1;

Mas gostaria de saber se existe uma forma mais limpa?

Estou usando o Linux, a propósito.


18
Uma maneira "mais limpa" de despejar o núcleo? .... bom;)
OJ.

5
Isso é fofo. Melhor ainda, use um booleano (enum em c?) ... if ( crash = TRUE) {/ OH SHI ... * /}
Ape-inago

3
BTW, esse método não funciona em todos os UNIXes. HPUX, por exemplo, permite que você leia e escreva NULL com impunidade (felizmente, isso é configurável).
paxdiablo

1
Acabei de aprender 3 ou 4 coisas novas excelentes. Obrigado.
Trevor Boyd Smith

@pax é mais uma razão para encontrar uma forma genérica;) Obrigado
hhafez

Respostas:


76

Aumentar o sinal de número 6 ( SIGABRTno Linux) é uma maneira de fazer isso (embora tenha em mente que SIGABRT não precisa ser 6 em todas as implementações POSIX, então você pode querer usar o SIGABRTpróprio valor se for qualquer coisa diferente de quick'n 'código de depuração sujo).

#include <signal.h>
: : :
raise (SIGABRT);

Chamar abort()também causará um despejo de memória, e você pode até fazer isso sem encerrar o processo, chamando fork()seguido por abort()no filho apenas - consulte esta resposta para obter detalhes.


7
SIGABRT não precisa ser o sinal número 6 (embora seja freqüentemente - e é, especificamente, no Linux).
Jonathan Leffler

4
Não, você está certo, não é, mas eu tendo a não me preocupar muito com a exatidão do código de depuração. Se isso escapar para o mundo selvagem, a limpeza do meu código é a menor das minhas preocupações :-)
paxdiablo

2
Chamar abort () pode ser inútil em algumas arquiteturas com alguns compiladores e algumas bibliotecas C (como gcc e glibc ou uClibc no ARM) porque a função abort () é declarada com um atributo noreturn e o compilador otimiza totalmente todas as informações de retorno, o que torna o arquivo principal inutilizável. Você não pode rastreá-lo após a chamada para aumentar () ou abortar (). Portanto, é muito melhor chamar raise (SIGABRT) diretamente ou kill (getpid (), SIGABRT), que é virtualmente o mesmo.
Alexander Amelkin

3
Desculpe, no ARM a mesma coisa acontece até com aumento (SIGABRT). Portanto, a única maneira de produzir um arquivo central rastreável é kill (getpid (), SIGABRT)
Alexander Amelkin

A dica para a ulimit -c unlimitedresposta de Suvesh Pratapa, me ajudou muito para esta resposta.
Boris Däppen

74

Alguns anos atrás, o Google lançou a biblioteca coredumper .

Visão geral

A biblioteca coredumper pode ser compilada em aplicativos para criar core dumps do programa em execução - sem encerrar. Ele oferece suporte a core dumps simples e multithread, mesmo se o kernel não oferecer suporte nativo a arquivos core multithread.

O Coredumper é distribuído sob os termos da Licença BSD.

Exemplo

Este não é um exemplo completo; ele simplesmente dá uma ideia de como é a API coredumper.

#include <google/coredumper.h>
...
WriteCoreDump('core.myprogram');
/* Keep going, we generated a core file,
 * but we didn't crash.
 */

Não é o que você estava pedindo, mas talvez seja ainda melhor :)


3
Fiquei inicialmente muito animado quando encontrei esta resposta. Mas o dumper de núcleo está parecendo muito velho e decrépito atualmente. Há até uma indicação de que não funciona mais nos kernels Linux contemporâneos: stackoverflow.com/questions/38314020/…
jefe2000

37

Conforme listado na página de manual do sinal , qualquer sinal com a ação listada como 'núcleo' forçará um despejo de núcleo. Alguns exemplos são:

SIGQUIT       3       Core    Quit from keyboard
SIGILL        4       Core    Illegal Instruction
SIGABRT       6       Core    Abort signal from abort(3)
SIGFPE        8       Core    Floating point exception
SIGSEGV      11       Core    Invalid memory reference

Certifique-se de habilitar core dumps:

ulimit -c unlimited

Obrigado, seu comentário sobre a ativação de core dumps com ulimit -c unlimitedajudou.

Como você definiria o ulimit de dentro do código? @ ks1322
Karan Joisher

@KaranJoisher Isso provavelmente vale outra pergunta, mas resumindo, você pode usar o setrlimit(RLIMIT_CORE, &core_limits);disponível via #include <sys/resource.h>. Você cria uma estrutura do tipo rlimite, em seguida, define os membros rlim_cure rlim_max.
Brent Writes Code



6

Outra maneira de gerar um dump principal:

$ bash
$ kill -s SIGSEGV $$

Basta criar uma nova instância do bash e eliminá-lo com o sinal especificado. O $$é o PID do shell. Caso contrário, você está matando seu bash atual e será desconectado, o terminal será fechado ou desconectado.

$ bash 
$ kill -s SIGABRT $$
$ bash
$ kill -s SIGFPE $$

Muito simples e útil!
firo

1
Eu gosto desse também. Pode até ser simplificado para bash -c 'kill -SIGSEGV $$'.
Christian Krause,

4

Você pode usar kill (2) para enviar sinal.

#include <sys/types.h>
#include <signal.h>
int kill(pid_t pid, int sig);

Assim,

kill(getpid(), SIGSEGV);

Sim. Adicionado isso à resposta.
Eugene Yokota

2

Às vezes, pode ser apropriado fazer algo assim:

int st = 0;
pid_t p = fork();

if (!p) {
    signal(SIGABRT, SIG_DFL);
    abort(); // having the coredump of the exact copy of the calling thread
} else {
    waitpid(p, &st, 0); // rip the zombie
}

// here the original process continues to live

Um problema com esta abordagem simples é que apenas um segmento será bombeado.


1
 #include <stdio.h>
 #include <stdlib.h>
 int main()
 {
   printf("\n");
   printf("Process is aborting\n");
   abort();
   printf("Control not reaching here\n");
   return 0;
 }

use essa abordagem onde quiser :)


0
#include <assert.h>
.
.
.
     assert(!"this should not happen");

Provavelmente precisa muck com NDEBUG para que esta declaração particular esteja ativa mesmo quando outras declarações não estão.
Rhys Ulerich
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.