GNU/Linux >> LINUX-Kenntnisse >  >> Linux

Erstellen und Debuggen von Linux-Dump-Dateien

Crash-Dump, Memory-Dump, Core-Dump, System-Dump … alle erzeugen das gleiche Ergebnis:eine Datei, die den Zustand des Speichers einer Anwendung zu einem bestimmten Zeitpunkt enthält – normalerweise, wenn die Anwendung abstürzt.

Zu wissen, wie man mit diesen Dateien umgeht, kann Ihnen helfen, die Grundursache(n) eines Fehlers zu finden. Selbst wenn Sie kein Entwickler sind, können auf Ihrem System erstellte Dump-Dateien sehr hilfreich (und zugänglich) sein, um Software zu verstehen.

Dies ist ein praxisorientierter Artikel. Sie können dem Beispiel folgen, indem Sie das Beispielanwendungs-Repository klonen mit:

git clone https://github.com/hANSIc99/core_dump_example.git

Wie sich Signale auf Dumps beziehen

Weitere Linux-Ressourcen

  • Spickzettel für Linux-Befehle
  • Spickzettel für fortgeschrittene Linux-Befehle
  • Kostenloser Online-Kurs:RHEL Technical Overview
  • Spickzettel für Linux-Netzwerke
  • SELinux-Spickzettel
  • Spickzettel für allgemeine Linux-Befehle
  • Was sind Linux-Container?
  • Unsere neuesten Linux-Artikel

Signale sind eine Art Interprozesskommunikation zwischen dem Betriebssystem und den Benutzeranwendungen. Linux verwendet die im POSIX-Standard definierten Signale. Auf Ihrem System finden Sie die in /usr/include/bits/signum-generic.h definierten Standardsignale . Es gibt auch eine informative Man-Signal-Seite, wenn Sie mehr über die Verwendung von Signalen in Ihrer Anwendung erfahren möchten. Einfach ausgedrückt verwendet Linux Signale, um weitere Aktivitäten auszulösen, je nachdem, ob sie erwartet oder unerwartet waren.

Wenn Sie eine laufende Anwendung beenden, erhält die Anwendung normalerweise den SIGTERM Signal. Da diese Art von Exit-Signal erwartet wird, erzeugt diese Aktion kein Speicherabbild.

Die folgenden Signale bewirken, dass eine Dump-Datei erstellt wird (Quelle:GNU C Library):

  • SIGFPE:Fehlerhafte arithmetische Operation
  • Siegel:Illegale Anweisung
  • SIGSEGV:Ungültiger Zugriff auf Speicher
  • SIGBUS:Busfehler
  • SIGABRT:Ein vom Programm erkannter und durch Aufruf von abort gemeldeter Fehler
  • SIGIOT:Auf Fedora als archaisch bezeichnet, wird dieses Signal verwendet, um auf abort() auszulösen auf einem PDP-11 und wird jetzt auf SIGABRT abgebildet

Dump-Dateien erstellen

Navigieren Sie zu core_dump_example Verzeichnis, führen Sie make aus , und führen Sie das Beispiel mit -c1 aus Schalter:

./coredump -c1

Die Anwendung sollte in Zustand 4 mit einem Fehler beendet werden:

"Abgebrochen (Speicherabzug geschrieben)" bedeutet grob übersetzt "Segmentation fault (core dumped)."

Ob ein Core-Dump erstellt wird oder nicht, wird durch die Ressourcengrenze des Benutzers bestimmt, der den Prozess ausführt. Sie können die Ressourcenlimits mit ulimit ändern Befehl.

Überprüfen Sie die aktuelle Einstellung für die Core-Dump-Erstellung:

ulimit -c

Wenn es unlimited ausgibt , dann verwendet es den (empfohlenen) Standardwert. Korrigieren Sie andernfalls das Limit mit:

ulimit -c unlimited

Geben Sie Folgendes ein, um das Erstellen von Core-Dumps zu deaktivieren:

ulimit -c 0

Die Zahl gibt die Ressource in Kilobyte an.

Was sind Core-Dumps?

Die Art und Weise, wie der Kernel Core-Dumps handhabt, ist definiert in:

/proc/sys/kernel/core_pattern

Ich verwende Fedora 31 und auf meinem System enthält die Datei:

/usr/lib/systemd/systemd-coredump %P %u %g %s %t %c %h

Dies zeigt, dass Core-Dumps an systemd-coredump weitergeleitet werden Nützlichkeit. Der Inhalt von core_pattern kann zwischen den verschiedenen Geschmacksrichtungen von Linux-Distributionen stark variieren. Wenn systemd-coredump verwendet wird, werden die Dump-Dateien komprimiert unter /var/lib/systemd/coredump gespeichert . Sie müssen die Dateien nicht direkt berühren; stattdessen können Sie coredumpctl verwenden . Zum Beispiel:

coredumpctl list

zeigt alle verfügbaren Dump-Dateien, die auf Ihrem System gespeichert sind.

Mit coredumpctl dump , können Sie Informationen aus der zuletzt gespeicherten Dump-Datei abrufen:

[stephan@localhost core_dump_example]$ ./coredump 
Application started…

(…….)

Message: Process 4598 (coredump) of user 1000 dumped core.

Stack trace of thread 4598:
#0 0x00007f4bbaf22625 __GI_raise (libc.so.6)
#1 0x00007f4bbaf0b8d9 __GI_abort (libc.so.6)
#2 0x00007f4bbaf664af __libc_message (libc.so.6)
#3 0x00007f4bbaf6da9c malloc_printerr (libc.so.6)
#4 0x00007f4bbaf6f49c _int_free (libc.so.6)
#5 0x000000000040120e n/a (/home/stephan/Dokumente/core_dump_example/coredump)
#6 0x00000000004013b1 n/a (/home/stephan/Dokumente/core_dump_example/coredump)
#7 0x00007f4bbaf0d1a3 __libc_start_main (libc.so.6)
#8 0x000000000040113e n/a (/home/stephan/Dokumente/core_dump_example/coredump)
Refusing to dump core to tty (use shell redirection or specify — output).

Dies zeigt, dass der Prozess von SIGABRT gestoppt wurde . Der Stack-Trace in dieser Ansicht ist nicht sehr detailliert, da er keine Funktionsnamen enthält. Allerdings mit coredumpctl debug , können Sie die Dump-Datei einfach mit einem Debugger (standardmäßig GDB) öffnen. Geben Sie bt ein (kurz für backtrace) um eine detailliertere Ansicht zu erhalten:

Core was generated by `./coredump -c1'.
Program terminated with signal SIGABRT, Aborted.
#0  __GI_raise (sig=sig@entry=6) at ../sysdeps/unix/sysv/linux/raise.c:50
50  return ret;
(gdb) bt
#0  __GI_raise (sig=sig@entry=6) at ../sysdeps/unix/sysv/linux/raise.c:50
#1  0x00007fc37a9aa8d9 in __GI_abort () at abort.c:79
#2  0x00007fc37aa054af in __libc_message (action=action@entry=do_abort, fmt=fmt@entry=0x7fc37ab14f4b "%s\n") at ../sysdeps/posix/libc_fatal.c:181
#3  0x00007fc37aa0ca9c in malloc_printerr (str=str@entry=0x7fc37ab130e0 "free(): invalid pointer") at malloc.c:5339
#4  0x00007fc37aa0e49c in _int_free (av=<optimized out>, p=<optimized out>, have_lock=0) at malloc.c:4173
#5  0x000000000040120e in freeSomething(void*) ()
#6  0x0000000000401401 in main ()

Die Speicheradressen:main() und freeSomething() sind im Vergleich zu nachfolgenden Frames ziemlich niedrig. Da Shared Objects auf einen Bereich am Ende des virtuellen Adressraums abgebildet werden, können Sie davon ausgehen, dass die SIGABRT wurde durch einen Aufruf in einer gemeinsam genutzten Bibliothek verursacht. Speicheradressen von gemeinsam genutzten Objekten sind zwischen Aufrufen nicht konstant, daher ist es völlig in Ordnung, wenn Sie zwischen Aufrufen unterschiedliche Adressen sehen.

Der Stacktrace zeigt, dass nachfolgende Aufrufe von malloc.c stammen , was darauf hinweist, dass etwas mit der Speicher(aufhebung)zuweisung schief gelaufen sein könnte.

Im Quellcode sieht man (auch ohne C++-Kenntnisse), dass versucht wurde, einen Zeiger freizugeben, der von einer Speicherverwaltungsfunktion nicht zurückgegeben wurde. Dies führt zu undefiniertem Verhalten und verursacht das SIGABRT :

void freeSomething(void *ptr){
    free(ptr);
}
int nTmp = 5;
int *ptrNull = &nTmp;
freeSomething(ptrNull);

Das Dienstprogramm systemd coredump kann unter /etc/systemd/coredump.conf konfiguriert werden . Die Rotation der Dump-Dateibereinigung kann in /etc/systemd/system/systemd-tmpfiles-clean.timer konfiguriert werden .

Weitere Informationen zu coredumpctl finden Sie hier auf seiner Manpage.

Kompilierung mit Debug-Symbolen

Öffnen Sie das Makefile und kommentieren Sie den letzten Teil von Zeile 9 aus. Es sollte jetzt so aussehen:

CFLAGS =-Wall -Werror -std=c++11 -g

Das -g switch ermöglicht es dem Compiler, Debug-Informationen zu erstellen. Starten Sie die Anwendung, diesmal mit dem -c2 Schalter:

./coredump -c2

Sie erhalten eine Gleitkommaausnahme. Öffnen Sie den Dump in GDB mit:

coredumpctl debug

Diesmal werden Sie direkt auf die Zeile im Quellcode verwiesen, die den Fehler verursacht hat:

Reading symbols from /home/stephan/Dokumente/core_dump_example/coredump…
[New LWP 6218]
Core was generated by `./coredump -c2'.
Program terminated with signal SIGFPE, Arithmetic exception.
#0 0x0000000000401233 in zeroDivide () at main.cpp:29
29 nRes = 5 / nDivider;
(gdb)

Geben Sie list ein um einen besseren Überblick über den Quellcode zu bekommen:

(gdb) list
24      int zeroDivide(){
25          int nDivider = 5;
26          int nRes = 0;
27          while(nDivider > 0){
28              nDivider--;
29              nRes = 5 / nDivider;
30          }
31          return nRes;
32      }

Verwenden Sie den Befehl info locals um die Werte der lokalen Variablen von dem Zeitpunkt abzurufen, an dem die Anwendung fehlgeschlagen ist:

(gdb) info locals
nDivider = 0
nRes = 5

In Kombination mit dem Quellcode können Sie sehen, dass Sie auf eine Division durch Null gestoßen sind:

nRes = 5 / 0

Schlussfolgerung

Wenn Sie wissen, wie Sie mit Speicherauszugsdateien umgehen, können Sie zufällige Fehler in einer Anwendung finden und beheben, die schwer zu reproduzieren sind. Und wenn es nicht Ihre Anwendung ist, hilft die Weiterleitung eines Core-Dumps an den Entwickler, das Problem zu finden und zu beheben.


Linux
  1. Finden Sie Dateien und Verzeichnisse in Linux wie ein Profi

  2. Erstellen, Löschen und Verwalten von Verzeichnissen unter Linux

  3. So archivieren und komprimieren Sie Dateien unter Linux

  4. Fehlerbehebung und Debugging für Linux-Netzwerke?

  5. Linux Dateien und Verzeichnisse löschen

So komprimieren Sie Dateien und Verzeichnisse unter Linux

Pigz – Dateien parallel unter Linux komprimieren und dekomprimieren

So installieren Sie Rclone unter Linux und Unix

Sparen Sie Platz, indem Sie Dateien und Ordner unter Linux komprimieren

Finden Sie Dateien und Verzeichnisse unter Linux ganz einfach

Freigabe von Dateien zwischen Linux Mint und Windows 10