So erstellen Sie programmgesteuert einen Core-Dump in C / C ++

93

Ich möchte einen Core-Dump an einer bestimmten Stelle in meiner C ++ - Anwendung erzwingen.

Ich weiß, dass ich es tun kann, indem ich so etwas mache wie:

int * crash = NULL;
*crash = 1;

Aber ich würde gerne wissen, ob es einen saubereren Weg gibt?

Ich benutze übrigens Linux.

hhafez
quelle
18
Ein "sauberer" Weg zum Core Dump? .... gut;)
ABl.
5
Das ist süß. Verwenden Sie besser noch einen Booleschen Wert (Aufzählung in c?) ... if ( Absturz = WAHR) {/ OH SHI ... * /}
Ape-inago
3
Übrigens funktioniert diese Methode nicht in allen UNIXes. Zum einen können Sie mit HPUX ungestraft NULL lesen und schreiben (zum Glück ist dies konfigurierbar).
Paxdiablo
1
Ich habe gerade 3 oder 4 tolle neue Dinge gelernt. Vielen Dank.
Trevor Boyd Smith
@pax das ist eher ein Grund, einen generischen Weg zu finden;) Danke
hhafez

Antworten:

76

Die Anhebung der Signalnummer 6 ( SIGABRTin Linux) ist eine Möglichkeit , es zu tun (obwohl bedenken Sie, dass SIGABRT ist nicht erforderlich in allen POSIX - Implementierungen sein 6 , so dass Sie die verwenden möchten SIGABRTWert selbst wenn dies etwas anderes als Quick'n ist 'Dirty Debug Code).

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

Das Aufrufen abort()führt auch zu einem Core-Dump, und Sie können dies sogar tun, ohne den Prozess zu beenden, indem Sie nur das untergeordnete Element aufrufen, fork()gefolgt von dieser Antwort . Weitere Informationen finden abort()Sie in dieser Antwort .

paxdiablo
quelle
7
SIGABRT muss nicht das Signal Nummer 6 sein (obwohl dies häufig der Fall ist - und insbesondere unter Linux).
Jonathan Leffler
4
Nein, Sie haben Recht, aber ich mache mir keine allzu großen Sorgen um die Richtigkeit des Debug-Codes. Wenn das in die Wildnis entkommt, ist die Sauberkeit meines Codes die geringste meiner Sorgen :-)
paxdiablo
2
Das Aufrufen von abort () kann auf einigen Architekturen mit einigen Compilern und einigen C-Bibliotheken (wie gcc und glibc oder uClibc auf ARM) unbrauchbar sein, da die Funktion abort () mit einem noreturn- Attribut deklariert ist und der Compiler alle Rückgabeinformationen vollständig optimiert. Das macht die Kerndatei unbrauchbar. Sie können es nicht nach dem Aufruf verfolgen, um sich selbst zu erhöhen () oder abzubrechen (). Es ist also viel besser, Raise (SIGABRT) direkt aufzurufen oder Kill (getpid (), SIGABRT) zu verwenden, was praktisch gleich ist.
Alexander Amelkin
3
Entschuldigung, auf ARM passiert dasselbe auch mit Raise (SIGABRT). Die einzige Möglichkeit, eine nachvollziehbare Kerndatei zu erstellen, ist kill (getpid (), SIGABRT)
Alexander Amelkin
Der Hinweis auf die ulimit -c unlimitedAntwort von Suvesh Pratapa hat mir bei dieser Antwort sehr geholfen.
Boris Däppen
74

Vor einigen Jahren hat Google die Coredumper- Bibliothek veröffentlicht.

Überblick

Die Coredumper-Bibliothek kann in Anwendungen kompiliert werden, um Core-Dumps des laufenden Programms zu erstellen - ohne zu beenden. Es unterstützt sowohl Single- als auch Multi-Threaded-Core-Dumps, auch wenn der Kernel Multi-Threaded-Core-Dateien nicht nativ unterstützt.

Coredumper wird unter den Bedingungen der BSD-Lizenz vertrieben.

Beispiel

Dies ist keineswegs ein vollständiges Beispiel; Es gibt Ihnen einfach ein Gefühl dafür, wie die Coredumper-API aussieht.

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

Es ist nicht das, wonach du gefragt hast, aber vielleicht ist es sogar noch besser :)

kurzlebig
quelle
3
Ich war anfangs ziemlich aufgeregt, als ich auf diese Antwort stieß. Aber der Kernkipper sieht heutzutage ziemlich alt und altersschwach aus. Es gibt sogar Hinweise darauf, dass es auf modernen Linux-Kerneln nicht mehr funktioniert: stackoverflow.com/questions/38314020/…
jefe2000
37

Wie in der Signal-Manpage aufgeführt , erzwingt jedes Signal mit der als "Kern" aufgeführten Aktion einen Kern-Dump. Einige Beispiele sind:

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

Stellen Sie sicher, dass Sie Core Dumps aktivieren:

ulimit -c unlimited
Suvesh Pratapa
quelle
Vielen Dank, Ihre Bemerkung zum Aktivieren von Core Dumps hat ulimit -c unlimitedgeholfen.
Wie würden Sie das ulimit aus dem Code heraus einstellen? @ ks1322
Karan Joisher
@KaranJoisher Das ist wahrscheinlich eine andere Frage wert, aber kurz gesagt können Sie setrlimit(RLIMIT_CORE, &core_limits);verfügbar über verwenden #include <sys/resource.h>. Sie erstellen eine Struktur vom Typ rlimitund legen dann die Mitglieder rlim_curund fest rlim_max.
Brent schreibt Code
31
#include <stdlib.h>   // C
//#include <cstdlib>  // C++

void core_dump(void)
{
    abort();
}
Jonathan Leffler
quelle
3
Warum nicht einfach abort()direkt anrufen ?
DepressedDaniel
5

Eine andere Möglichkeit, einen Core Dump zu generieren:

$ bash
$ kill -s SIGSEGV $$

Erstellen Sie einfach eine neue Instanz der Bash und beenden Sie sie mit dem angegebenen Signal. Das $$ist die PID der Shell. Andernfalls beenden Sie Ihre aktuelle Bash und werden abgemeldet, das Terminal geschlossen oder getrennt.

$ bash 
$ kill -s SIGABRT $$
$ bash
$ kill -s SIGFPE $$
Zonk
quelle
Sehr einfach und nützlich!
Firo
1
Ich mag das auch. Es kann sogar vereinfacht werden bash -c 'kill -SIGSEGV $$'.
Christian Krause
4

Sie können kill (2) verwenden , um ein Signal zu senden.

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

So,

kill(getpid(), SIGSEGV);
Eugene Yokota
quelle
Jep. Fügte das der Antwort hinzu.
Eugene Yokota
2

Manchmal kann es angebracht sein, so etwas zu tun:

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

Ein Problem bei diesem einfachen Ansatz besteht darin, dass nur ein Thread entleert wird.

rka444
quelle
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;
 }

Verwenden Sie diesen Ansatz, wo immer Sie wollen :)

karthik339
quelle
0
#include <assert.h>
.
.
.
     assert(!"this should not happen");
Sigjuice
quelle
Müssen wahrscheinlich mit NDEBUG Mist spielen, damit diese bestimmte Behauptung aktiv ist, auch wenn andere Behauptungen dies nicht sind.
Rhys Ulerich