Ich habe ein Programm, das irgendwo eine nicht erfasste Ausnahme auslöst. Ich erhalte nur einen Bericht über eine ausgelöste Ausnahme und keine Informationen darüber, wo sie ausgelöst wurde. Es erscheint unlogisch, wenn ein Programm, das Debug-Symbole enthält, mich nicht darüber informiert, wo in meinem Code eine Ausnahme generiert wurde.
Gibt es eine Möglichkeit zu erkennen, woher meine Ausnahmen kommen, wenn ich nicht 'catch throw' in gdb gesetzt und für jede einzelne ausgelöste Ausnahme eine Rückverfolgung aufgerufen habe?
Antworten:
Hier einige Informationen , die möglicherweise in Debuggen Problem von Nutzen sein
Wenn eine Ausnahme nicht erfasst wird, wird die spezielle Bibliotheksfunktion
std::terminate()
automatisch aufgerufen. Beenden ist eigentlich ein Zeiger auf eine Funktion und der Standardwert ist die Standard-C-Bibliotheksfunktionstd::abort()
. Wenn für eine nicht erfasste Ausnahme keine Bereinigungen auftreten † , kann dies beim Debuggen dieses Problems hilfreich sein, da keine Destruktoren aufgerufen werden.† Es ist implementierungsdefiniert, ob der Stapel vor dem
std::terminate()
Aufruf abgewickelt wird oder nicht .Ein Aufruf von
abort()
ist häufig hilfreich, um einen Core-Dump zu generieren, der analysiert werden kann, um die Ursache der Ausnahme zu ermitteln. Stellen Sie sicher, dass Sie Core Dumps überulimit -c unlimited
(Linux) aktivieren .Sie können Ihre eigene
terminate()
Funktion mit installierenstd::set_terminate()
. Sie sollten in der Lage sein, einen Haltepunkt für Ihre Beendigungsfunktion in gdb festzulegen. Möglicherweise können Sie aus Ihrerterminate()
Funktion einen Stack-Backtrace generieren. Dieser Backtrace kann dabei helfen, den Ort der Ausnahme zu ermitteln.Es gibt eine kurze Diskussion über nicht erfasste Ausnahmen in Bruce Eckels Denken in C ++, 2. Ausgabe , die ebenfalls hilfreich sein kann.
Da standardmäßig
terminate()
Aufrufe ausgeführtabort()
werden (die standardmäßig einSIGABRT
Signal verursachen ), können Sie möglicherweise einenSIGABRT
Handler festlegen und dann eine Stapelrückverfolgung aus dem Signalhandler heraus drucken . Diese Rückverfolgung kann bei der Identifizierung des Speicherorts der Ausnahme hilfreich sein.Hinweis: Ich sage möglicherweise, weil C ++ die nicht-lokale Fehlerbehandlung durch die Verwendung von Sprachkonstrukten unterstützt, um die Fehlerbehandlung und den Berichtscode vom normalen Code zu trennen. Der Fangblock kann und befindet sich häufig in einer anderen Funktion / Methode als der Wurfpunkt. In den Kommentaren wurde ich auch darauf hingewiesen (danke Dan ), dass die Implementierung definiert ist, ob der Stapel vor dem
terminate()
Aufruf abgewickelt wird oder nicht .Update: Ich habe ein Linux-Testprogramm namens aufgerufen, das eine Rückverfolgung in einem
terminate()
Funktionssatz überset_terminate()
und eine andere in einem Signalhandler für generiertSIGABRT
. Beide Rückverfolgungen zeigen den Ort der nicht behandelten Ausnahme korrekt an.Update 2: Dank eines Blogposts über das Abfangen nicht erfasster Ausnahmen innerhalb von terminate habe ich einige neue Tricks gelernt. einschließlich des erneuten Auslösens der nicht erfassten Ausnahme innerhalb des Terminate-Handlers. Es ist wichtig zu beachten, dass die leere
throw
Anweisung im benutzerdefinierten Terminate-Handler mit GCC funktioniert und keine tragbare Lösung ist.Code:
Ausgabe:
quelle
main
) und dann aufgerufen würdeterminate()
. Ihr Beispiel zeigt jedoch, dass überhaupt kein Abwickeln erfolgt, was sehr cool ist.throw(int)
Spezifikation ist nicht erforderlich. 2) Dasuc->uc_mcontext.eip
ist wahrscheinlich sehr plattformabhängig (z. B. Verwendung...rip
auf einer 64-Bit-Plattform). 3) Kompilieren Sie mit,-rdynamic
damit Sie Backtrace-Symbole erhalten. 4) Laufen Sie./a.out 2>&1 | c++filt
, um hübsche Backtrace-Symbole zu erhalten.((sig_ucontext_t *)userContext)->uc_mcontext.fault_address;
arbeitete für mein ARM-ZielWie Sie sagen, können wir in gdb 'catch throw' verwenden und für jede einzelne ausgelöste Ausnahme 'backtrace' aufrufen. Während dies normalerweise zu mühsam ist, um es manuell zu tun, ermöglicht gdb die Automatisierung des Prozesses. Auf diese Weise können Sie die Rückverfolgung aller Ausnahmen sehen, die ausgelöst werden, einschließlich der letzten nicht erfassten:
gdb>
Ohne weitere manuelle Eingriffe werden viele Rückverfolgungen generiert, einschließlich einer für die letzte nicht erfasste Ausnahme:
Hier ist ein großartiger Blog-Beitrag, der dies zusammenfasst: http://741mhz.com/throw-stacktrace [auf archive.org]
quelle
Sie können ein Makro wie folgt erstellen:
... und es gibt Ihnen den Ort, an dem die Ausnahme ausgelöst wird (zugegebenermaßen nicht die Stapelverfolgung). Sie müssen Ihre Ausnahmen von einer Basisklasse ableiten, die den obigen Konstruktor verwendet.
quelle
throw new excation(...)
aberthrow exception(...)
C ++ ist nicht Java,Sie haben keine Informationen darüber übergeben, welches Betriebssystem / welchen Compiler Sie verwenden.
In Visual Studio C ++ können Ausnahmen instrumentiert werden.
Siehe "Visual C ++ Exception-Handling Instrumentation" auf ddj.com
Mein Artikel "Postmortem Debugging" , ebenfalls auf ddj.com, enthält Code zur Verwendung der strukturierten Win32-Ausnahmebehandlung (von der Instrumentierung verwendet) für die Protokollierung usw.
quelle
Sie können die wichtigsten engen Stellen in Ihrem Code markieren
noexcept
, um eine Ausnahme zu lokalisieren, und dann libunwind verwenden (einfach-lunwind
zu den Linker-Parametern hinzufügen ) (getestet mitclang++ 3.6
):demagle.hpp:
demangle.cpp:
backtrace.hpp:
backtrace.cpp:
backtrace_on_terminate.hpp:
Es gibt einen guten Artikel zu diesem Thema.
quelle
Ich habe Code, um dies in Windows / Visual Studio zu tun. Lassen Sie mich wissen, wenn Sie eine Gliederung wünschen. Ich weiß nicht, wie ich es für dwarf2-Code machen soll. Ein kurzer Blick auf Google schlägt vor, dass es in libgcc eine Funktion _Unwind_Backtrace gibt, die wahrscheinlich Teil dessen ist, was Sie brauchen.
quelle
Überprüfen Sie diesen Thread, vielleicht hilft es:
Alle nicht behandelten C ++ - Ausnahmen abfangen?
Ich habe gute Erfahrungen mit dieser Software gemacht:
http://www.codeproject.com/KB/applications/blackbox.aspx
Es kann einen Stack-Trace für jede nicht behandelte Ausnahme in eine Datei drucken.
quelle
exception thrown foo.c@54, ..., re-thrown bar.c@54, ....
ohne ihn manuell ausführen zu müssen.