Wie generiere ich einen Core Dump unter Linux bei einem Segmentierungsfehler?

217

Ich habe einen Prozess unter Linux, bei dem ein Segmentierungsfehler auftritt. Wie kann ich ihm sagen, dass er einen Core-Dump generieren soll, wenn er fehlschlägt?

Nathan Fellman
quelle
1
So sehen Sie es später: stackoverflow.com/questions/8305866/…
Ciro Santilli 郝海东 冠状 病 六四 事件 事件 14.

Antworten:

249

Dies hängt davon ab, welche Shell Sie verwenden. Wenn Sie bash verwenden, steuert der Befehl ulimit verschiedene Einstellungen in Bezug auf die Programmausführung, z. B. ob Sie den Core sichern sollten. Wenn Sie tippen

ulimit -c unlimited

dann wird das bash sagen, dass seine Programme Kerne jeder Größe ausgeben können. Sie können eine Größe wie 52 MB anstelle von unbegrenzt angeben, wenn Sie möchten. In der Praxis sollte dies jedoch nicht erforderlich sein, da die Größe der Kerndateien für Sie wahrscheinlich nie ein Problem darstellt.

In tcsh würden Sie eingeben

limit coredumpsize unlimited
Eli Courtwright
quelle
21
@lzprgmr: Zur Verdeutlichung: Der Grund, warum Core-Dumps nicht standardmäßig generiert werden, ist, dass das Limit nicht festgelegt und / oder auf 0 gesetzt ist, wodurch verhindert wird, dass der Core-Dump ausgeführt wird. Durch die Festlegung eines unbegrenzten Limits garantieren wir, dass immer Core-Dumps generiert werden können.
Eli Courtwright
6
Dieser Link geht tiefer und bietet einige weitere Optionen, um die Generierung von Core-Dumps unter Linux zu ermöglichen. Der einzige Nachteil ist, dass einige Befehle / Einstellungen ungeklärt bleiben.
Salsa
6
In Bash 4.1.2 (1) können keine Freigabegrenzen wie 52M angegeben werden, was zu einer ungültigen Nummernfehlermeldung führt. Die Manpage gibt an, dass "Werte in Schritten von 1024 Byte angegeben sind".
a1an
4
Nun, ich hatte ein "kleines" OpenGL-Projekt, das einmal etwas Seltsames getan hat und einen Absturz des X-Servers verursacht hat. Als ich mich zurückmeldete, sah ich eine niedliche kleine 17-GB-Kerndatei (auf einer 25-GB-Partition). Es ist definitiv eine gute Idee, die Größe der Kerndatei begrenzt zu halten :)
IceCool
1
@PolarisUser: Wenn Sie sicherstellen möchten, dass Ihre Partition nicht gegessen wird, empfehle ich, ein Limit von etwa 1 Gig festzulegen. Das sollte groß genug sein, um jeden vernünftigen Core-Dump zu verarbeiten, ohne den gesamten verbleibenden Festplattenspeicher zu verbrauchen.
Eli Courtwright
60

Wie oben erläutert, wird hier die eigentliche Frage gestellt, wie Core Dumps auf einem System aktiviert werden können, auf dem sie nicht aktiviert sind. Diese Frage wird hier beantwortet.

Wenn Sie hierher gekommen sind, um zu erfahren, wie Sie einen Core-Dump für einen blockierten Prozess generieren, lautet die Antwort

gcore <pid>

Wenn gcore auf Ihrem System nicht verfügbar ist, dann

kill -ABRT <pid>

Verwenden Sie kill -SEGV nicht, da dies häufig einen Signalhandler aufruft, der die Diagnose des festgefahrenen Prozesses erschwert

George Co.
quelle
Ich denke, es ist weitaus wahrscheinlicher, dass -ABRTein Signal-Handler -SEGVaufgerufen wird als , da ein Abbruch eher wiederherstellbar ist als ein Segfault. (Wenn Sie einen Segfault behandeln, wird dieser normalerweise erst wieder ausgelöst, sobald Ihr Handler beendet wird.) Eine bessere Signalauswahl für die Erzeugung eines Core-Dumps ist -QUIT.
Celticminstrel
32

Führen Sie Folgendes aus, um zu überprüfen, wo die Core-Dumps generiert werden:

sysctl kernel.core_pattern

oder:

cat /proc/sys/kernel/core_pattern

Wo %eist der Prozessname und %tdie Systemzeit. Sie können es ändern /etc/sysctl.confund neu laden durch sysctl -p.

Wenn die Kerndateien nicht generiert werden (testen Sie sie mit: sleep 10 &und killall -SIGSEGV sleep), überprüfen Sie die Grenzwerte mit : ulimit -a.

Wenn Ihre Kerndateigröße begrenzt ist, führen Sie Folgendes aus:

ulimit -c unlimited

um es unbegrenzt zu machen.

Testen Sie dann erneut, ob das Core-Dumping erfolgreich ist. Nach der Anzeige des Segmentierungsfehlers wird "(Core-Dumping)" angezeigt:

Segmentierungsfehler: 11 (Core Dumped)

Siehe auch: Core Dumped - aber Core-Datei befindet sich nicht im aktuellen Verzeichnis?


Ubuntu

In Ubuntu werden die Core-Dumps von Apport verwaltet und können sich in befinden /var/crash/. In stabilen Releases ist es jedoch standardmäßig deaktiviert.

Weitere Informationen finden Sie unter: Wo finde ich den Core Dump in Ubuntu? .

Mac OS

Informationen zu macOS finden Sie unter: Wie werden Core-Dumps in Mac OS X generiert?

Kenorb
quelle
3
Damit Ubuntu schnell zum normalen Verhalten zurückkehren kann (Speichern einer Kerndatei im aktuellen Verzeichnis), beenden Sie einfach den Apport-Dienst mit "sudo service apport stop". Beachten Sie außerdem, dass diese Einstellung auf dem Hostsystem und nicht im Container gesteuert wird, wenn Sie im Docker ausgeführt werden.
Digicrat
26

Was ich am Ende getan habe, war, gdb an den Prozess anzuhängen, bevor er abstürzte, und dann, als er den Segfault bekam, habe ich den generate-core-fileBefehl ausgeführt. Diese erzwungene Erzeugung eines Kerndumps.

Nathan Fellman
quelle
Wie haben Sie gdb an den Prozess angehängt?
Chani
6
Um auf Ritwik G zu antworten und einen Prozess an gdb anzuhängen, starten Sie einfach gdb und geben Sie 'attach <pid>' ein, wobei <pid> die Pid-Nummer des Prozesses ist, den Sie anhängen möchten.
Jean-Dominique Frattini
(abgekürzt als ge)
user202729
Wenn sie eine neue Frage haben, sollten sie eine neue Frage stellen, anstatt sie in einem Kommentar zu stellen.
user202729
Seltsame Sache ist, dass ich bereits eingestellt ulimit -chabe unlimited, aber die Kerndatei ist noch nicht erstellt, die generate-core-fileDatei in der GDB-Sitzung erstellt die Kerndatei, danke.
CodyChan
19

Vielleicht könnten Sie es auf diese Weise tun. Dieses Programm ist eine Demonstration, wie ein Segmentierungsfehler abgefangen und an einen Debugger weitergeleitet wird (dies ist der ursprüngliche Code, der unter verwendet wird AIX), und druckt die Stapelverfolgung bis zum Punkt eines Segmentierungsfehlers. Sie müssen die sprintfVariable ändern, die gdbim Fall von Linux verwendet werden soll.

#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 */
}

Möglicherweise müssen Sie zusätzlich einen Parameter hinzufügen, damit gdb den Kern entleert, wie hier in diesem Blog hier gezeigt .

t0mm13b
quelle
16

Es gibt weitere Faktoren, die die Erzeugung eines Core-Dumps beeinflussen können. Ich bin auf Folgendes gestoßen:

  • Das Verzeichnis für den Speicherauszug muss beschreibbar sein. Standardmäßig ist dies das aktuelle Verzeichnis des Prozesses. Dies kann jedoch durch Festlegen geändert werden /proc/sys/kernel/core_pattern.
  • Unter bestimmten Umständen kann der Kernelwert in /proc/sys/fs/suid_dumpableverhindern, dass der Kern generiert wird.

Es gibt weitere Situationen, die die in der Manpage beschriebene Generierung verhindern können man core.

mlutescu
quelle
9

Gehen Sie wie folgt vor, um den Core Dump zu aktivieren:

  1. Im /etc/profileKommentar der Zeile:

    # ulimit -S -c 0 > /dev/null 2>&1
  2. Im /etc/security/limits.confKommentar aus der Zeile:

    *               soft    core            0
  3. Führen Sie das cmd aus limit coredumpsize unlimitedund überprüfen Sie es mit 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
    #
  4. Um zu überprüfen, ob die Core-Datei geschrieben wird, können Sie den zugehörigen Prozess mit cmd beenden kill -s SEGV <PID>(sollte nicht benötigt werden, nur für den Fall, dass keine Core-Datei geschrieben wird, kann dies als Überprüfung verwendet werden):

    # kill -s SEGV <PID>

Nachdem die Corefile geschrieben wurde, müssen Sie die Coredump-Einstellungen in den zugehörigen Dateien (1./2./3.) Wieder deaktivieren!

Edgar Jordi
quelle
9

Für Ubuntu 14.04

  1. Überprüfen Sie, ob der Core Dump aktiviert ist:

    ulimit -a
  2. Eine der Zeilen sollte sein:

    core file size          (blocks, -c) unlimited
  3. Wenn nicht :

    gedit ~/.bashrcund ulimit -c unlimitedam Ende der Datei hinzufügen und speichern, Terminal erneut ausführen.

  4. Erstellen Sie Ihre Anwendung mit Debug-Informationen:

    In Makefile -O0 -g

  5. Führen Sie eine Anwendung aus, die einen Core-Dump erstellt (Core-Dump-Datei mit dem Namen 'core' sollte in der Nähe der Datei application_name erstellt werden):

    ./application_name
  6. Unter gdb ausführen:

    gdb application_name core
mrgloom
quelle
In Schritt 3, Wie wird das Terminal erneut ausgeführt? Meinst du Neustart?
Naveen
@Naveen Nein, schließen Sie einfach das Terminal und öffnen Sie das neue. Anscheinend können Sie das ulimit -c unlimitedTerminal auch nur für eine temporäre Lösung ~/.bashrceinfügen , da nur für die Bearbeitung ein Neustart des Terminals erforderlich ist, damit Änderungen wirksam werden.
Mrgloom
4

Standardmäßig erhalten Sie eine Kerndatei. Überprüfen Sie, ob das aktuelle Verzeichnis des Prozesses beschreibbar ist oder keine Kerndatei erstellt wird.

Mark Harrison
quelle
4
Mit "aktuelles Verzeichnis des Prozesses" meinen Sie das $ cwd zum Zeitpunkt der Ausführung des Prozesses? ~ / abc> / usr / bin / cat def Wenn cat abstürzt, ist das aktuelle Verzeichnis in Frage ~ / abc oder / usr / bin?
Nathan Fellman
5
~ / abc. Hmm, Kommentare müssen 15 Zeichen lang sein!
Mark Harrison
5
Dies wäre das aktuelle Verzeichnis zum Zeitpunkt der SEGV. Außerdem schreiben Prozesse, die mit einem anderen effektiven Benutzer und / oder einer anderen Gruppe als dem tatsächlichen Benutzer / der tatsächlichen Gruppe ausgeführt werden, keine Kerndateien.
Darron
2

Es ist besser, den Core Dump mithilfe eines Systemaufrufs programmgesteuert einzuschalten setrlimit.

Beispiel:

#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));
}
kgbook
quelle
warum ist das besser
Nathan Fellman
Kerndatei nach dem Absturz generiert, keine Notwendigkeit ulimit -c unlimitedin der Befehlszeilenumgebung, und dann die Anwendung erneut ausführen.
kgbook
Ich möchte nicht jedes Mal einen Core-Dump, wenn er abstürzt, nur wenn ein Benutzer mich als Entwickler kontaktiert, um ihn anzusehen. Wenn es 100 Mal abstürzt, brauche ich keine 100 Core-Dumps zum Anschauen.
Nathan Fellman
In diesem Fall besser zu verwenden ulimit -c unlimited. Sie können auch mit marco definition kompilieren. Die Anwendung enthält kein enable_core_dumpSymbol, wenn dieses Makro bei der Veröffentlichung nicht definiert wird, und Sie erhalten einen Core-Dump, der durch die Debug-Version ersetzt wird.
kgbook
Selbst wenn es durch ein Makro qualifiziert ist, muss ich dennoch neu kompilieren, wenn ich einen Core-Dump generieren möchte, anstatt einfach einen Befehl in der Shell auszuführen, bevor ich ihn erneut ausführe.
Nathan Fellman
1

Es ist erwähnenswert, dass, wenn Sie ein System eingerichtet haben, die Dinge ein bisschen anders sind. Bei der Einrichtung werden die Kerndateien normalerweise mithilfe des core_patternsysctl-Werts durchgeleitet systemd-coredump(8). Die Kerndateigröße rlimit wird normalerweise bereits als "unbegrenzt" konfiguriert.

Es ist dann möglich, die Core-Dumps mit abzurufen coredumpctl(1).

Die Speicherung von Core Dumps usw. wird von konfiguriert coredump.conf(5). Es gibt Beispiele, wie Sie die Kerndateien in der Manpage coredumpctl abrufen können, aber kurz gesagt würde es so aussehen:

Suchen Sie die Kerndatei:

[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

Holen Sie sich die Kerndatei:

[vps@phoenix]~$ coredumpctl -o test_me.core dump 16163
Pawel Veselov
quelle
0

Ubuntu 19.04

Alle anderen Antworten selbst haben mir nicht geholfen. Aber die folgende Zusammenfassung hat den Job gemacht

Erstellen Sie ~/.config/apport/settingsmit folgendem Inhalt:

[main]
unpackaged=true

(Dies weist Apport an, auch Core-Dumps für benutzerdefinierte Apps zu schreiben.)

überprüfen : ulimit -c. Wenn es 0 ausgibt, beheben Sie es mit

ulimit -c unlimited

Nur für den Fall, dass Apport neu gestartet wird:

sudo systemctl restart apport

Absturzdateien werden jetzt geschrieben /var/crash/. Sie können sie jedoch nicht mit gdb verwenden. Um sie mit gdb zu verwenden, verwenden Sie

apport-unpack <location_of_report> <target_directory>

Weitere Informationen:

  • Einige Antworten schlagen eine Änderung vor core_pattern. Beachten Sie, dass diese Datei beim Neustart möglicherweise vom Apport-Dienst überschrieben wird.
  • Das einfache Stoppen von Apport hat den Job nicht erledigt
  • Der ulimit -cWert wird möglicherweise automatisch geändert, wenn Sie andere Antworten im Web ausprobieren. Überprüfen Sie dies regelmäßig, während Sie die Erstellung Ihres Core-Dumps einrichten.

Verweise:

DarkTrick
quelle