2009-06-11 11 views
75

Je voudrais forcer un vidage de noyau à un emplacement spécifique dans mon application C++.Comment faire pour provoquer un vidage de noyau en C/C++ par programme

Je sais que je peux le faire en faisant quelque chose comme:

int * crash = NULL; 
*crash = 1; 

Mais je voudrais savoir s'il y a un moyen plus propre? J'utilise Linux en passant.

+15

Un "plus propre" façon de plantera? .... bon un;) –

+4

C'est mignon. Mieux encore utiliser un booléen (enum in c?) ... if (* crash = TRUE) {/ * OH SHI ... * /} –

+3

BTW, cette méthode ne fonctionne pas dans tous les UNIX. HPUX, pour sa part, vous permet de lire et d'écrire NULL en toute impunité (heureusement, c'est configurable). – paxdiablo

Répondre

64

Raising du numéro de signal 6 (SIGABRT sous Linux) est un moyen de le faire (bien que SIGABRT ne soit pas requis pour être 6 dans toutes les implémentations POSIX, vous pouvez donc utiliser la valeur SIGABRT si elle est autre que quick'n 'code de débogage sale).

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

Appel abort() sera également provoquer une décharge de base, et vous pouvez même le faire sans mettre fin à votre processus en appelant fork() suivi par abort() chez l'enfant seulement - voir this answer pour plus de détails.

+7

SIGABRT n'est pas requis pour être le numéro de signal 6 (bien qu'il soit souvent - et est, spécifiquement, sur Linux). –

+4

Non, vous avez raison, ce n'est pas le cas, mais je ne m'inquiète pas trop de l'exactitude du code de débogage. Si ça s'échappe dans la nature, la propreté de mon code est le moindre de mes soucis :-) – paxdiablo

+2

Appeler abort() peut être inutile sur certaines architectures avec quelques compilateurs et certaines bibliothèques C (comme gcc et glibc ou uClibc sur ARM) car La fonction abort() est déclarée avec un attribut __noreturn__ et le compilateur optimise totalement toutes les informations de retour, ce qui rend le fichier core inutilisable. Vous ne pouvez pas le tracer après l'appel de raise() ou abort() lui-même. Il est donc préférable d'appeler raise (SIGABRT) directement ou kill (getpid(), SIGABRT), ce qui est pratiquement le même. –

30

Comme indiqué dans le signal manpage, tout signal dont l'action est répertoriée comme «noyau» forcera une sauvegarde de base. Voici quelques exemples:

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 

Assurez-vous que vous activez fichiers core:

ulimit -c unlimited 
+0

bon point ~~~~~ –

+0

Merci, votre remarque sur l'activation des décharges de base avec «ulimit -c unlimited» aidé. –

30
#include <stdlib.h> // C 
//#include <cstdlib> // C++ 

void core_dump(void) 
{ 
    abort(); 
} 
+1

Pourquoi ne pas simplement appeler 'abort()' directement? – DepressedDaniel

4

Vous pouvez utiliser kill(2) pour envoyer un signal.

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

Ainsi,

kill(getpid(), SIGSEGV); 
+0

Donc kill (getpid(), SIGxxx) ;? –

+0

Yup. Ajouté à la réponse. –

+2

SIGKILL ne jette pas core ... –

68

Il y a quelques années, Google a publié la bibliothèque coredumper.

Vue d'ensemble

La bibliothèque coredumper peut être compilé dans des applications pour créer des décharges essentielles du programme en cours - sans terminer. Il prend en charge les vidages de core mono et multi-thread, même si le noyau ne supporte pas nativement les fichiers core multithread. Coredumper est distribué selon les termes de la licence BSD.

Exemple

Ceci n'est en aucun cas un exemple complet; cela vous donne simplement une idée de ce à quoi ressemble l'API coredumper.

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

Ce n'est pas ce que vous demandez, mais peut-être il est encore mieux :)

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

Probablement besoin de muck avec NDEBUG donc cette assertion particulière est active même si les autres assertions ne le sont pas. –

1

Parfois, il peut être approprié de faire qch comme ceci:

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 

One problème avec cette approche simple est qu'un seul thread sera corédigé.

3

Une autre façon de générer une décharge de base:

$ bash 
$ kill -s SIGSEGV $$ 

Il suffit de créer une nouvelle instance de la bash et tuez-le avec le signal spécifié. Le $$ est le PID de le shell. Sinon, vous tuez votre bash actuel et serez déconnecté, terminal fermé ou déconnecté.

$ bash 
$ kill -s SIGABRT $$ 
$ bash 
$ kill -s SIGFPE $$ 
+0

Très simple et utile! – firo

+1

J'aime aussi celui-là. Il peut même être simplifié pour 'bash -c 'kill -SIGSEGV $$''. –

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

utiliser cette approche où vous voulez :)

Questions connexes