#endif
#ifndef QT_NO_UNWIND
+# include "qcoreapplication.h"
# define UNW_LOCAL_ONLY
# include <libunwind.h>
# include <cxxabi.h>
QT_THROW(std::bad_alloc());
}
-static inline void qt_print_backtrace()
-{
#ifndef QT_NO_UNWIND
+static void qt_print_backtrace()
+{
unw_cursor_t cursor;
unw_context_t context;
printf("qt_print_backtrace: unable to obtain symbol name for this frame\n");
}
}
+}
+
+typedef void (*QCrashHandler)(int);
+
+static bool qt_set_crash_handler(QCrashHandler handler) {
+ sigset_t mask;
+ if (::sigemptyset(&mask) != 0) {
+ ::fprintf(stderr, "sigaddset error: %s\n", ::strerror(errno));
+ return false;
+ }
+
+#define HANDLE_SIGNAL(x) \
+ ::signal(x, handler); \
+ if (::sigaddset(&mask, x) != 0) { \
+ ::fprintf(stderr, "sigaddset error: %s\n", ::strerror(errno)); \
+ return false; \
+ }
+
+#ifdef SIGSEGV
+ HANDLE_SIGNAL(SIGSEGV)
+#endif
+#ifdef SIGBUS
+ HANDLE_SIGNAL(SIGBUS)
#endif
+#ifdef SIGFPE
+ HANDLE_SIGNAL(SIGFPE)
+#endif
+#ifdef SIGILL
+ HANDLE_SIGNAL(SIGILL)
+#endif
+#ifdef SIGABRT
+ HANDLE_SIGNAL(SIGABRT)
+#endif
+
+#undef HANDLE_SIGNAL
+
+ if (::sigprocmask(SIG_UNBLOCK, &mask, nullptr) != 0) {
+ ::fprintf(stderr, "sigprocmask error: %s\n", ::strerror(errno));
+ return false;
+ }
+
+ return true;
+}
+
+static void qt_crash_handler(int sig) {
+ const QByteArray name = QCoreApplication::applicationName().toLatin1();
+ const std::string pid = std::to_string(::getpid());
+
+ if (name.isEmpty()) {
+ ::fprintf(stderr, "PID %s crashed\n", pid.c_str());
+ } else {
+ ::fprintf(stderr, "%s with PID %s crashed\n", name.constData(), pid.c_str());
+ }
+
+ qt_set_crash_handler(SIG_DFL);
+
+ qt_print_backtrace();
+
+ ::raise(sig);
}
+int qt_install_crash_handler()
+{
+ qt_set_crash_handler(qt_crash_handler);
+ return 0;
+}
+
+Q_CONSTRUCTOR_FUNCTION(qt_install_crash_handler);
+#endif
+
/*
The Q_ASSERT macro calls this function when the test fails.
*/
void qt_assert(const char *assertion, const char *file, int line)
{
- qt_print_backtrace();
+#ifndef QT_NO_UNWIND
+ // don't print backtrace twice if abort() will be called in qt_message_output()
+ if (qgetenv("QT_FATAL_WARNINGS").isNull())
+ qt_print_backtrace();
+#endif
qFatal("ASSERT: \"%s\" in file %s, line %d", assertion, file, line);
}
*/
void qt_assert_x(const char *where, const char *what, const char *file, int line)
{
- qt_print_backtrace();
+#ifndef QT_NO_UNWIND
+ // don't print backtrace twice if abort() will be called in qt_message_output()
+ if (qgetenv("QT_FATAL_WARNINGS").isNull())
+ qt_print_backtrace();
+#endif
qFatal("ASSERT failure in %s: \"%s\", file %s, line %d", where, what, file, line);
}