Wie generieren Sie automatisch einen stacktrace, wenn mein Programm stürzt ab
Ich arbeite auf Linux mit dem GCC compiler. Wenn mein C++ Programm abstürzt, würde ich es gerne automatisch erzeugen eines stacktrace.
Mein Programm ausgeführt wird, die von vielen verschiedenen Benutzern, und es läuft auch auf Linux, Windows und Macintosh (alle Versionen kompiliert mit gcc
).
Ich möchte mein Programm erzeugen zu können, einen stack-trace, wenn es abstürzt und der Benutzer das nächste mal läuft es, es wird Sie Fragen, ob es in Ordnung ist, senden die stack-trace zu mir, so kann ich das problem zurückzuverfolgen. Ich kann mit dem versenden der info an mich, aber ich weiß nicht, wie zu generieren der trace-Zeichenfolge. Irgendwelche Ideen?
- Welches OS, welche shell?
- backtrace und backtrace_symbols_fd nicht async-signal-safe. Sie sollten nicht verwenden, diese Funktion im signal-handler
- backtrace_symbols Aufrufe von malloc, darf also nicht verwendet werden, in einem signal-handler. Die anderen beiden Funktionen (backtrace und backtrace_symbols_fd) dieses problem nicht haben, und sind Häufig in der signal-Handler.
- das ist falsch backtrace_symbols_fd in der Regel nicht rufen malloc kann aber, wenn etwas schief geht in seiner catch_error block
- Es "kann" in dem Sinne, dass es keine POSIX-Spezifikation für backtrace_symbols_fd (oder jede backtrace), aber GNU/Linux ist backtrace_symbols_fd angegeben ist, nie rufen malloc, als pro linux.die.net/man/3/backtrace_symbols_fd . Daher ist es sicher davon ausgehen, dass es nie aufrufen von malloc auf Linux.
- Wie kommt es zum Absturz?
- Nicht sicher, ob nicht behandelte Ausnahmen zu qualifizieren als "Programm-Absturz", aber die Methode zum drucken eines stacktrace bei exceptions geworfen werden beschrieben in dieser Antwort könnte auch interessant für Sie sein.
Du musst angemeldet sein, um einen Kommentar abzugeben.
Für Linux und ich glaube, Mac OS X, wenn Sie gcc verwenden, oder jeder compiler, verwendet die glibc verwenden, können Sie den backtrace () - Funktionen in
execinfo.h
zum drucken eines stacktrace und würdevoll beenden, wenn man einen segmentation fault. Die Dokumentation finden Sie in der libc-manual.Hier ein Beispiel für ein Programm, dass installiert eine
SIGSEGV
handler und druckt einen stacktrace zustderr
wenn es segfaults. Diebaz()
Funktion hier bewirkt, dass der segfault ausgelöst handler:Kompilieren mit
-g -rdynamic
bekommt man info-symbol in der Ausgabe, die glibc verwenden können, um einen schönen stacktrace:Ausführung dieses bekommt Sie in dieser Ausgabe:
Dies zeigt die Last-Modul -, offset -, und-Funktion, die jeden frame im stack kam. Hier sehen Sie die signal-handler, die oben auf dem Stapel, und die libc-Funktionen, bevor
main
nebenmain
,foo
,bar
, undbaz
.sigaction()
in der libc. Während Ihr backtrace richtig zu sein scheint, habe ich manchmal festgestellt, dass zusätzliche Schritte notwendig sind, um eine tatsächliche Position des Fehlers wird in der backtrace wie es sein kann, überschrieben mitsigaction()
durch den kernel.catchsegv
ist nicht das, was der OP braucht, aber ist genial für den Fang von speicherzugriffsverletzungen und bekommen alle Informationen.exit()
sicher von einem signal-handler. Verwenden_exit()
oder_Exit()
.exit()
bitte beachten Sie, dass probacktrace_symbol_fd(3)
, müssen Sie kostenlos diearray
nachdem Sie fertig sind.man 7 signal
, Jede einzelne der Funktionen, dass Sie den handler anrufen ist nicht async-signal-safe, führt zu undefinierten Verhalten. In der Praxis, Ihr Prozess könnte deadlock (mit-lpthread
) oder corrupt memory (ohne).*(int*)0=1;
würde ausreichen, um zu generieren segfault statt 2 Zeilenabort()
. Eine weitere option: versuchen Sie die Registrierung Ihres signal-handler mitsigaction
ohne mitSA_NODEFER
(signal
entspricht in der RegelSA_RESETHAND | SA_NODEFER
). Das signal wird nur dann geliefert werden, nachdem Rückkehr aus dem Signalhandler.Linux
Während der Nutzung der backtrace () - Funktionen in execinfo.h drucken Sie einen stacktrace und würdevoll beenden, wenn man einen segmentation fault hat bereits vorgeschlagen worden, ich sehe keine Erwähnung von den Feinheiten notwendig, um sicherzustellen, die resultierende Ablaufverfolgung Punkte zu den eigentlichen Ort des Fehlers (zumindest für einige Architekturen - x86 - & ARM).
Die ersten beiden Einträge im stack-frame Kette, wenn man in der signal-handler enthalten eine return-Adresse in die signal-handler und eine innen sigaction() in der libc. Der stack-frame der letzten Funktion, die aufgerufen wird, bevor das signal (das ist der Ort der Störung) verloren.
Code
Ausgabe
Alle Gefahren der Aufruf der backtrace () - Funktionen in einem signal-handler immer noch vorhanden und sollte nicht übersehen werden, aber ich finde die Funktionalität, die ich hier beschrieben sehr hilfreich beim Debuggen von Abstürzen.
Es ist wichtig zu beachten, dass das Beispiel, das ich zur Verfügung gestellt wird entwickelt/getestet auf Linux für x86. Ich habe auch erfolgreich umgesetzt wird dieses über den ARM mit
uc_mcontext.arm_pc
stattuc_mcontext.eip
.Hier ist ein link zu dem Artikel, wo ich gelernt, die details für diese Umsetzung:
http://www.linuxjournal.com/article/6391
-rdynamic
zu beauftragen, der linker alle Symbole, die nicht nur dem dynamischen symbol-Tabelle. Dies ermöglichtbacktrace_symbols()
zum konvertieren von Adressen zu Funktionsnamenaddr2line
Befehl irgendwie zu bekommen, die genau die Zeile, in der der Absturz aufgetreten ist?glibc
uc_mcontext
nicht enthalten ein Feld mit dem Nameneip
. Es ist jetzt ein array muss indiziert werden,uc_mcontext.gregs[REG_EIP]
entspricht.uc_mcontext
array alsuc_mcontext.gregs[REG_RIP]
.struct sigcontext
kann nicht gefunden werden von macOS 10.14, das ist POSIX-konform, so ist dies ein glibc-spezifische Programm. Auch auf Ubuntu 16.04 (4.4.0 Linux als kernel), die Zeile mit dem symbol dercrash()
erscheint zweimal, statt nur einmal, wie dargestellt in der Antwort.Es sogar noch einfacher als "Mann backtrace", es ist eine wenig dokumentierte Bibliothek (GNU-spezifisch) verteilt mit der glibc als libSegFault.so, das war glaube ich wurde geschrieben von Ulrich Drepper zu unterstützen, das Programm catchsegv (siehe "man catchsegv").
Dieser gibt uns 3 Möglichkeiten. Anstatt zu laufen "- Programm-o-hai":
Innerhalb von catchsegv:
Link mit libSegFault zur Laufzeit:
Link mit libSegFault zur compile-Zeit:
In allen 3 Fällen, erhalten Sie klarer von Ablaufverfolgungen mit weniger Optimierung (gcc -O0 oder -O1) und debugging-Symbole (gcc -g). Andernfalls können Sie nur am Ende mit ein Haufen Speicher-Adressen.
Können Sie fangen auch mehr Signale für stack-traces mit so etwas wie:
Wird die Ausgabe wie folgt Aussehen (beachten Sie den backtrace an der Unterseite):
Wenn Sie wissen wollen, die blutigen details, die beste Quelle ist leider die Quelle: Siehe http://sourceware.org/git/?p=glibc.git;a=blob;f=debug/segfault.c und das übergeordnete Verzeichnis http://sourceware.org/git/?p=glibc.git;a=tree;f=debug
-Wl,--no-as-needed
an den compiler-flags. Ansonstenld
wird in der Tat nicht link gegenlibSegFault
, weil es erkennt, dass die binäre keine seiner Symbole.Obwohl ein richtige Antwort zur Verfügung gestellt wurde, das beschreibt, wie die Verwendung der GNU libc
backtrace()
Funktion1 und ich meine eigene Antwort, die beschreibt, wie ein backtrace aus einem signal-handler zeigt auf die tatsächliche Lage der Störung2, ich don ' T sehen jede Erwähnung von demangling C++ - Symbole Ausgang aus dem backtrace.Beim Erwerb von Ablaufverfolgungen aus einem C++ - Programm, die Ausgabe kann ausgeführt werden durch
c++filt
1 zu demangle Symbolen oder durch die Verwendungabi::__cxa_demangle
1 direkt.Beachten Sie, dass
c++filt
und__cxa_demangle
sind GCC-spezifischenDen folgenden C++ - Linux-Beispiel verwendet die gleichen signal-handler wie mein andere Antwort und zeigt, wie
c++filt
können verwendet werden, um demangle der Symbole.Code:
Ausgabe (
./test
):Demangled Ausgabe (
./test 2>&1 | c++filt
):Folgende baut auf den signal handler aus meiner original Antwort und ersetzen kann die signal-handler im obigen Beispiel zu demonstrieren, wie
abi::__cxa_demangle
kann verwendet werden, um demangle die Symbole. Dieser signal-handler erzeugt die gleiche demangled Ausgabe wie im obigen Beispiel.Code:
Sein könnte, lohnt ein Blick auf Google Breakpad, eine cross-Plattform crash-dump-generator und Werkzeuge zum verarbeiten der Deponien.
Wollte Sie nicht Ihr Betriebssystem, so ist das schwer zu beantworten. Wenn Sie mit einem system basierend auf gnu-libc, Sie können möglicherweise verwenden Sie die libc-Funktion
backtrace()
.GCC hat auch zwei gelieferten, die Ihnen helfen können, aber die kann oder kann nicht umgesetzt werden voll auf Ihre Architektur, und die sind
__builtin_frame_address
und__builtin_return_address
. Beide wollen eine sofortige integer-Ebene (durch eine sofortige, ich meine, es kann nicht eine variable sein). Wenn__builtin_frame_address
für ein bestimmtes Maß nicht null ist, sollte es sicher sein, rufen Sie die return-Adresse auf der gleichen Ebene.ulimit -c <value>
setzt die core-Datei Größenbeschränkung auf unix. Standardmäßig wird die core file size limit 0 ist. Sie können sehen, Ihreulimit
Werte mitulimit -a
.auch, wenn Sie Ihr Programm innerhalb von gdb, es wird halt Ihr Programm auf "segmentierungsverletzungen" (
SIGSEGV
, in der Regel, wenn Sie aufgerufen, ein Stück Erinnerung, Sie hatte nicht zugewiesen) oder Sie können Haltepunkte.ddd und nemiver sind frontends für den gdb, die machen die Arbeit viel einfacher für den Anfänger.
Danke an enthusiasticgeek für die Zeichnung meine Aufmerksamkeit auf die addr2line-Dienstprogramm.
Ich geschrieben habe eine quick-and-dirty-Skript zum verarbeiten der Ausgabe der Antwort hier:
(Dank jschmier!) mit der addr2line-Dienstprogramm.
Das script akzeptiert ein einziges argument: Den Namen der Datei mit der Ausgabe von jschmier Dienstprogramm.
Sollte die Ausgabe etwas ausdrucken, wie im folgenden für jede Stufe der Spur:
Code:
Es ist wichtig zu beachten, dass, wenn Sie erzeugen eine core-Datei benötigen Sie den gdb-tool, um es zu betrachten. Für gdb Sinn der core-Datei, Sie müssen sagen, gcc instrument der binary mit debug-Symbole: um dies zu tun, kompilieren Sie mit dem -g flag:
Dann können Sie entweder "ulimit -c unlimited" zu lassen, ein core-dump, oder einfach führen Sie Ihr Programm innerhalb von gdb. Mir gefällt der zweite Ansatz mehr:
Ich hoffe, das hilft.
gdb
direkt von Ihrem Absturz Programm. Setup-handler für SIGSEGV, SEGILL, SIGBUS, SIGFPE, der Aufruf von gdb. Details: stackoverflow.com/questions/3151779/... Der Vorteil ist, dass Sie schöne, kommentierte backtrace wie inbt full
, ebenfalls erhalten Sie die Stacktraces aller threads.Ive wurde Blick auf dieses problem für eine Weile.
Und tief in der Google Performance Tools README
http://code.google.com/p/google-perftools/source/browse/trunk/README
spricht über libunwind
http://www.nongnu.org/libunwind/
Würde gerne Meinungen zu hören von dieser Bibliothek.
Das problem mit -rdynamic ist, dass es kann erhöhen Sie die Größe der binären relativ deutlich in einigen Fällen
Einige Versionen von libc enthalten Funktionen, die sich mit der stack-traces; Sie könnten in der Lage sein, Sie zu nutzen:
http://www.gnu.org/software/libc/manual/html_node/Backtraces.html
Ich erinnere mich, mit libunwind vor langer Zeit, um stack-traces, aber es kann nicht sein, auf Ihrer Plattform unterstützt.
Können Sie DeathHandler - kleine C++ - Klasse, die tut alles für Sie, zuverlässig.
execlp()
durchführen addr2line Anrufe... wäre schön voll bleiben im eigenen Programm (das ist möglich, indem die addr2line-code in irgendeiner form)Vergessen zur änderung Ihrer Quellen und einige hacks mit backtrace () - Funktion oder ein macro - dies sind nur schlechte Lösungen.
Als eine richtig funktionierende Lösung, ich würde Beratung:
Dieser druckt einwandfrei lesbaren backtrace des Programms in lesbarer Weise (mit Quell-Dateinamen und Zeilennummern).
Darüber hinaus eignet sich dieser Ansatz gibt Ihnen die Freiheit zu automatisieren Ihrem system:
ein kurzes Skript, dass prüft ob der Prozess erzeugt einen core-dump, und dann schicken Sie Ablaufverfolgungen per E-Mail an Entwickler, oder melden Sie diese in eine logging-system.
ist eine system-variable, die erlauben, eine core-dump nach Ihrer Anwendung abstürzt. In diesem Fall unbegrenzt. Suchen Sie nach einer Datei namens core im selben Verzeichnis. Stellen Sie sicher, dass Sie kompiliert den code mit Debuginformationen aktiviert!
hinsichtlich
limit coredumpsize unlimited
gewinnen: Wie etwa StackWalk64 http://msdn.microsoft.com/en-us/library/ms680650.aspx
StackWalk64
erfordert, dass Sie das Schiff debug-Symbole mit dem code. Das ist in der Regel nicht wünschenswert, da macht es reverse-engineering Ihrer Anwendung einfacher, eine ganze Menge. Bei Windows gibt es eine einfacher Lösung, die einen besseren Weg, Informationen: WER und haben Sie schreiben ein mini-dump auf nicht behandelte Ausnahmen. Eine einzige Registrierung ist erforderlich, um dies zu ermöglichen.Betrachten:
Mann 3 backtrace
Und:
Diese sind GNU-Erweiterungen.
Finden Sie die Stack-Trace-Funktion in ACE (ADAPTIVE Communication Environment). Es ist bereits geschrieben und deckt alle wichtigen Plattformen (und mehr). Die Bibliothek ist BSD-ähnlichen Lizenz, so können Sie auch copy/paste den code, wenn Sie nicht verwenden möchten, ass.
Ich kann mit Hilfe der Linux-version: die Funktion backtrace, backtrace_symbols und backtrace_symbols_fd verwendet werden kann. Finden Sie in den entsprechenden manual pages.
*nix:
Sie abfangen können SIGSEGV (in der Regel wird dieses signal ausgelöst wird, bevor es abstürzt) und halten Sie die info in eine Datei. (neben der core-Datei, die Sie verwenden können, um zu Debuggen mit gdb zum Beispiel).
gewinnen:
Überprüfen Sie diese von msdn.
Können Sie auch einen Blick auf die google chrome-code, um zu sehen, wie es verarbeitet abstürzt. Es hat eine schöne exception-handling-Mechanismus.
Fand ich, dass @tgamblin Lösung ist nicht vollständig.
Es nicht in den Griff mit stackoverflow.
Ich denke, weil durch die Standard-signal-handler aufgerufen wird mit dem gleichen stack und
SIGSEGV wird zweimal geworfen. Zu schützen, die Sie benötigen, registrieren Sie einen unabhängigen stack für die signal-handler.
Überprüfen Sie dies mit folgenden code. Standardmäßig wird der handler fehlschlägt. Mit den vorgegebenen Makros STACK_OVERFLOW es ist alles in Ordnung.
Ich würde den code, der erzeugt einen stack-trace für die Speicherbelegung in Visual Leak Detector. Dies funktioniert nur auf Win32, obwohl.
Ich habe gesehen, dass viele Antworten hier durchführen einer signal-handler und dann beenden.
Das ist der Weg zu gehen, aber erinnere mich an eine sehr wichtige Tatsache: Wenn Sie wollen, um die core-dump für die generierten Fehler Sie können nicht angerufen
exit(status)
. Rufen Sieabort()
statt!Den neuen König in der Stadt angekommen ist
https://github.com/bombela/backward-cpp
1-header an Stelle im code und 1 Bibliothek zu installieren.
Persönlich nenne ich es mit dieser Funktion
Zusätzlich zu den oben genannten Antworten, hier, wie Sie Debian Linux OS core-dump erzeugen
Geben Sie den folgenden unten: “kernel.core_pattern platziert wird = /home//coredumps/%e_%t.dump". (%e, werden die Prozess-Namen, und %t wird die system-Zeit)
Prüfen /proc/sys/kernel/core_pattern platziert wird und stellen Sie sicher, dass dies dem entspricht, was Sie gerade eingegeben haben in.
Als Windows-only-Lösung, können Sie das äquivalent von einem stack-trace (mit viel, viel mehr Informationen) mit Windows Error Reporting. Mit nur ein paar registry-Einträge, es kann eingestellt werden, bis zu sammeln von Benutzermodus-dumps:
Können Sie die registry-Einträge von Ihrem Installateur, die über die erforderlichen Berechtigungen.
Erstellung eines user-mode-dump hat folgende Vorteile gegenüber der Erzeugung eines stack-trace auf dem client:
Beachten, dass WER kann nur ausgelöst werden, wenn eine Anwendung abgestürzt ist (d.h. das system beenden eines Prozesses aufgrund einer unbehandelten Ausnahme).
MiniDumpWriteDump
können jederzeit genannt werden. Dies kann hilfreich sein, wenn Sie brauchen, um einen dump der aktuellen Zustand zu diagnostizieren Probleme, die andere als ein Absturz.Pflichtlektüre, wenn Sie wollen, dass die Bewertung der Anwendbarkeit der mini-dumps:
Sieht es aus wie in einer der letzten c++ - boost-version erschien Bibliothek zu bieten genau das, was Sie wollen, wahrscheinlich würde der code Multiplattform.
Es ist boost::stacktrace, die Sie verwenden können, wie wie in den boost-sample:
In Linux kompilieren Sie den code oben:
Beispiel backtrace kopiert von boost-Dokumentation:
Unter Linux/unix/MacOSX verwenden Sie die core-Dateien (Sie können Sie mit ulimit oder kompatibel system call). Unter Windows verwenden Sie die Microsoft-Fehlerberichterstattung (können Sie partner und erhalten Sie Zugriff auf Ihre Anwendung-crash-Daten).
Vergaß ich die GNOME-tech "apport", aber ich weiß nicht viel über es zu benutzen. Es wird verwendet, um generieren stacktraces und andere Diagnostik für die Verarbeitung und können automatisch Fehler. Es ist sicherlich lohnt sich Einchecken.
Wenn Sie immer noch wollen, es alleine zu machen, wie ich es Tat können Sie einen link gegen
bfd
und vermeiden Sie die Verwendungaddr2line
wie ich es hier getan habe:https://github.com/gnif/LookingGlass/blob/master/common/src/crash.linux.c
Dieses Beispiel erzeugt die Ausgabe: