diff --git a/src/LyX.cpp b/src/LyX.cpp index b7848311b8..98c5705917 100644 --- a/src/LyX.cpp +++ b/src/LyX.cpp @@ -667,7 +667,7 @@ static void error_handler(int err_sig) if (!msg.empty()) { lyxerr << "\nlyx: " << msg << endl; // try to make a GUI message - Alert::error(_("LyX crashed!"), msg); + Alert::error(_("LyX crashed!"), msg, true); } // Deinstall the signal handlers diff --git a/src/frontends/alert.h b/src/frontends/alert.h index 4f05234297..b96ca1e1d8 100644 --- a/src/frontends/alert.h +++ b/src/frontends/alert.h @@ -48,8 +48,9 @@ void warning(docstring const & title, docstring const & message, /** * Display a warning to the user. Title should be a short (general) summary. * Only use this if the user cannot perform some remedial action. + * On some systems it is possible to show a backtrace. */ -void error(docstring const & title, docstring const & message); +void error(docstring const & title, docstring const & message, bool backtrace = false); /** * Informational message. Use very very sparingly. That is, you must diff --git a/src/frontends/qt4/GuiAlert.cpp b/src/frontends/qt4/GuiAlert.cpp index 4e9a8e4c2a..14cce933e4 100644 --- a/src/frontends/qt4/GuiAlert.cpp +++ b/src/frontends/qt4/GuiAlert.cpp @@ -24,6 +24,7 @@ #include "support/debug.h" #include "support/docstring.h" #include "support/lstrings.h" +#include "support/lassert.h" #include "support/ProgressInterface.h" #include @@ -197,12 +198,17 @@ void warning(docstring const & title0, docstring const & message, title0, message, askshowagain); } -void doError(docstring const & title0, docstring const & message) +void doError(docstring const & title0, docstring const & message, bool backtrace) { lyxerr << "Error: " << title0 << '\n' << "----------------------------------------\n" << message << endl; + QString details; + if (backtrace) { + details = QString::fromLocal8Bit(to_local8bit(printCallStack()).c_str()); + } + if (!use_gui) return; @@ -223,7 +229,8 @@ void doError(docstring const & title0, docstring const & message) ProgressInterface::instance()->error( toqstr(title), - toqstr(message)); + toqstr(message), + details); qApp->restoreOverrideCursor(); @@ -231,14 +238,14 @@ void doError(docstring const & title0, docstring const & message) theApp()->startLongOperation(); } -void error(docstring const & title0, docstring const & message) +void error(docstring const & title0, docstring const & message, bool backtrace) { #ifdef EXPORT_in_THREAD InGuiThread().call(&doError, #else doError( #endif - title0, message); + title0, message, backtrace); } void doInformation(docstring const & title0, docstring const & message) diff --git a/src/frontends/qt4/GuiProgress.cpp b/src/frontends/qt4/GuiProgress.cpp index ab8c6bd3cf..a44438d489 100644 --- a/src/frontends/qt4/GuiProgress.cpp +++ b/src/frontends/qt4/GuiProgress.cpp @@ -56,8 +56,8 @@ GuiProgress::GuiProgress() SLOT(doWarning(QString const &, QString const &))); connect(this, SIGNAL(toggleWarning(QString const &, QString const &, QString const &)), SLOT(doToggleWarning(QString const &, QString const &, QString const &))); - connect(this, SIGNAL(error(QString const &, QString const &)), - SLOT(doError(QString const &, QString const &))); + connect(this, SIGNAL(error(QString const &, QString const &, QString const &)), + SLOT(doError(QString const &, QString const &, QString const &))); connect(this, SIGNAL(information(QString const &, QString const &)), SLOT(doInformation(QString const &, QString const &))); connect(this, SIGNAL(triggerFlush()), @@ -183,9 +183,13 @@ void GuiProgress::doToggleWarning(QString const & title, QString const & msg, QS } -void GuiProgress::doError(QString const & title, QString const & message) +void GuiProgress::doError(QString const & title, QString const & message, QString const & details) { - QMessageBox::critical(qApp->focusWidget(), title, message); + QMessageBox box(QMessageBox::Critical, title, message, QMessageBox::Ok, qApp->focusWidget()); + if (!details.isEmpty()) { + box.setDetailedText(details); + } + box.exec(); } diff --git a/src/frontends/qt4/GuiProgress.h b/src/frontends/qt4/GuiProgress.h index 9bb8b23034..80ab47a558 100644 --- a/src/frontends/qt4/GuiProgress.h +++ b/src/frontends/qt4/GuiProgress.h @@ -62,7 +62,7 @@ Q_SIGNALS: // Alert interface void warning(QString const & title, QString const & message); void toggleWarning(QString const & title, QString const & msg, QString const & formatted); - void error(QString const & title, QString const & message); + void error(QString const & title, QString const & message, QString const & details = QString()); void information(QString const & title, QString const & message); private Q_SLOTS: @@ -74,7 +74,7 @@ private Q_SLOTS: void doWarning(QString const &, QString const &); void doToggleWarning(QString const & title, QString const & msg, QString const & formatted); - void doError(QString const &, QString const &); + void doError(QString const &, QString const &, QString const &); void doInformation(QString const &, QString const &); void updateWithLyXErr(); diff --git a/src/support/CMakeLists.txt b/src/support/CMakeLists.txt index b0d1c6db20..4a018e8cce 100644 --- a/src/support/CMakeLists.txt +++ b/src/support/CMakeLists.txt @@ -41,6 +41,10 @@ else() set(support_linkback_headers "") endif() +if(UNIX AND CMAKE_COMPILER_IS_GNUCC AND NOT APPLE) + add_definitions(-DLYX_CALLSTACK_PRINTING) +endif() + add_subdirectory(tests) # needed to compile tex2lyx in merged mode diff --git a/src/support/ProgressInterface.h b/src/support/ProgressInterface.h index 1efb79a7e3..4a9a1edb68 100644 --- a/src/support/ProgressInterface.h +++ b/src/support/ProgressInterface.h @@ -36,7 +36,7 @@ public: /// Alert interface virtual void warning(QString const & title, QString const & message) = 0; virtual void toggleWarning(QString const & title, QString const & msg, QString const & formatted) = 0; - virtual void error(QString const & title, QString const & message) = 0; + virtual void error(QString const & title, QString const & message, QString const & details) = 0; virtual void information(QString const & title, QString const & message) = 0; virtual int prompt(docstring const & title, docstring const & question, int default_button, int cancel_button, diff --git a/src/support/Systemcall.cpp b/src/support/Systemcall.cpp index dc76b3d44c..467f04bd84 100644 --- a/src/support/Systemcall.cpp +++ b/src/support/Systemcall.cpp @@ -71,7 +71,7 @@ public: void warning(QString const &, QString const &) {} void toggleWarning(QString const &, QString const &, QString const &) {} - void error(QString const &, QString const &) {} + void error(QString const &, QString const &, QString const &) {} void information(QString const &, QString const &) {} int prompt(docstring const &, docstring const &, int default_but, int, docstring const &, docstring const &) { return default_but; } diff --git a/src/support/lassert.cpp b/src/support/lassert.cpp index 02e64bf7bf..281330e52c 100644 --- a/src/support/lassert.cpp +++ b/src/support/lassert.cpp @@ -20,9 +20,8 @@ #include +#include -//#define LYX_CALLSTACK_PRINTING -// must be linked with -rdynamic #ifdef LYX_CALLSTACK_PRINTING #include #include @@ -87,11 +86,12 @@ void doAppErr(char const * expr, char const * file, long line) } -//TODO Return as string, so call stack could be used in dialogs. -void printCallStack() +docstring printCallStack() { -#ifdef LYX_CALLSTACK_PRINTING - const int depth = 50; +#ifndef LYX_CALLSTACK_PRINTING + return docstring(); +#else + const int depth = 200; // get void*'s for all entries on the stack void* array[depth]; @@ -99,9 +99,9 @@ void printCallStack() char** messages = backtrace_symbols(array, size); - for (size_t i = 0; i < size && messages != NULL; i++) { - std::string orig(messages[i]); - // extract mangled: bin/lyx2.0(_ZN3lyx7support7packageEv+0x32) [0x8a2e02b] + docstring bt; + for (size_t i = 1; i < size && messages != NULL; i++) { + const std::string orig(messages[i]); char* mangled = 0; for (char *p = messages[i]; *p; ++p) { if (*p == '(') { @@ -112,15 +112,16 @@ void printCallStack() break; } } - int err = 0; - char* demangled = abi::__cxa_demangle(mangled, 0, 0, &err); - if (err == 0) { - fprintf(stderr, "[bt]: (%d) %s %s\n", i, messages[i], demangled); - free((void*)demangled); - } else { - fprintf(stderr, "[bt]: (%d) %s\n", i, orig.c_str()); - } + int status = 0; + const char* demangled = abi::__cxa_demangle(mangled, 0, 0, &status); + const QByteArray line = QString("(%1) %2: %3\n").arg(i, 3).arg(messages[i]) + .arg(demangled ? demangled : orig.c_str()).toLocal8Bit(); + free((void*)demangled); + + fprintf(stderr, "%s", line.constData()); + bt += from_local8bit(line.constData()); } + return bt; #endif } diff --git a/src/support/lassert.h b/src/support/lassert.h index 5e152e05bc..f9328f3581 100644 --- a/src/support/lassert.h +++ b/src/support/lassert.h @@ -66,7 +66,7 @@ void doBufErr(char const * expr, char const * file, long line); void doAppErr(char const * expr, char const * file, long line); /// Print demangled callstack to stderr -void printCallStack(); +docstring printCallStack(); } // namespace lyx