From 68e30de763c43ac6d00268a097897584ec35f37e Mon Sep 17 00:00:00 2001 From: Christophe Dumez Date: Sun, 18 Jan 2009 15:12:38 +0000 Subject: [PATCH] BUGFIX: qBittorrent now prints backtrace in terminal when segfaulting --- Changelog | 1 + qcm/libtorrent-rasterbar.qcm | 1 + src/main.cpp | 16 ++++-- src/src.pro | 4 +- src/stacktrace.h | 94 ++++++++++++++++++++++++++++++++++++ 5 files changed, 112 insertions(+), 4 deletions(-) create mode 100644 src/stacktrace.h diff --git a/Changelog b/Changelog index ec18b9c40..2729f2bf7 100644 --- a/Changelog +++ b/Changelog @@ -1,5 +1,6 @@ * Unknown - Christophe Dumez - v1.3.1 - BUGFIX: Torrents paused due to an I/O error were displayed as queued + - BUGFIX: qBittorrent now prints backtrace in terminal when segfaulting - I18N: Updated Bulgarian and Greek translations * Fri Jan 9 2009 - Christophe Dumez - v1.3.0 diff --git a/qcm/libtorrent-rasterbar.qcm b/qcm/libtorrent-rasterbar.qcm index 019ca5872..f215bdb30 100644 --- a/qcm/libtorrent-rasterbar.qcm +++ b/qcm/libtorrent-rasterbar.qcm @@ -6,6 +6,7 @@ arg: with-libtorrent-lib=[path], Path to libtorrent-rasterbar library files arg: with-libtorrent-static-lib=[path], Path to libtorrent-rasterbar .a file -----END QCMOD----- */ +// see Conf::findPkgConfig class qc_libtorrent_rasterbar : public ConfObj { public: diff --git a/src/main.cpp b/src/main.cpp index 58a7e3013..8cadab37d 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -45,6 +45,8 @@ #endif #ifndef Q_WS_WIN #include + #include + #include "stacktrace.h" #endif #include @@ -59,6 +61,13 @@ QApplication *app; qDebug("Catching SIGTERM, exiting cleanly"); app->exit(); } + void sigsegvHandler(int) { + std::cerr << "\n\n*************************************************************\n"; + std::cerr << "Catching SIGSEGV, please report a bug at http://bug.qbittorrent.org\nand provide the following backtrace:\n"; + print_stacktrace(); + std::raise(SIGINT); + std::abort(); + } #endif void useStyle(QApplication *app, int style){ @@ -177,6 +186,10 @@ int main(int argc, char *argv[]){ app->installTranslator(&translator); app->setApplicationName(QString::fromUtf8("qBittorrent")); app->setQuitOnLastWindowClosed(false); +#ifndef Q_WS_WIN + signal(SIGTERM, sigtermHandler); + signal(SIGSEGV, sigsegvHandler); +#endif // Read torrents given on command line QStringList torrentCmdLine = app->arguments(); // Remove first argument (program name) @@ -184,9 +197,6 @@ int main(int argc, char *argv[]){ GUI *window = new GUI(0, torrentCmdLine); splash->finish(window); delete splash; -#ifndef Q_WS_WIN - signal(SIGTERM, sigtermHandler); -#endif int ret = app->exec(); delete window; delete app; diff --git a/src/src.pro b/src/src.pro index 1541f4916..7f49e6a8d 100644 --- a/src/src.pro +++ b/src/src.pro @@ -87,6 +87,7 @@ contains(DEBUG_MODE, 0) { } #QMAKE_CXXFLAGS_RELEASE += -fwrapv #QMAKE_CXXFLAGS_DEBUG += -fwrapv +unix:QMAKE_LFLAGS_SHAPP += -rdynamic CONFIG += link_pkgconfig PKGCONFIG += "libtorrent-rasterbar libcurl" @@ -177,7 +178,8 @@ HEADERS += GUI.h \ TrackersAdditionDlg.h \ searchTab.h \ console_imp.h \ - ico.h + ico.h \ + stacktrace.h FORMS += MainWindow.ui \ options.ui \ about.ui \ diff --git a/src/stacktrace.h b/src/stacktrace.h new file mode 100644 index 000000000..48dfa9b3b --- /dev/null +++ b/src/stacktrace.h @@ -0,0 +1,94 @@ +// stacktrace.h (c) 2008, Timo Bingmann from http://idlebox.net/ +// published under the WTFPL v2.0 + +#ifndef _STACKTRACE_H_ +#define _STACKTRACE_H_ + +#include +#include +#include +#include + +/** Print a demangled stack backtrace of the caller function to FILE* out. */ +static inline void print_stacktrace(FILE *out = stderr, unsigned int max_frames = 63) +{ + fprintf(out, "stack trace:\n"); + + // storage array for stack trace address data + void* addrlist[max_frames+1]; + + // retrieve current stack addresses + int addrlen = backtrace(addrlist, sizeof(addrlist) / sizeof(void*)); + + if (addrlen == 0) { + fprintf(out, " \n"); + return; + } + + // resolve addresses into strings containing "filename(function+address)", + // this array must be free()-ed + char** symbollist = backtrace_symbols(addrlist, addrlen); + + // allocate string which will be filled with the demangled function name + size_t funcnamesize = 256; + char* funcname = (char*)malloc(funcnamesize); + + // iterate over the returned symbol lines. skip the first, it is the + // address of this function. + for (int i = 2; i < addrlen; i++) + { + char *begin_name = 0, *begin_offset = 0, *end_offset = 0; + + // find parentheses and +address offset surrounding the mangled name: + // ./module(function+0x15c) [0x8048a6d] + //fprintf(out, "%s TT\n", symbollist[i]); + for (char *p = symbollist[i]; *p; ++p) + { + if (*p == '(') + begin_name = p; + else if (*p == '+') + begin_offset = p; + else if (*p == ')' && begin_offset) { + end_offset = p; + break; + } + } + + if (begin_name && begin_offset && end_offset + && begin_name < begin_offset) + { + *begin_name++ = '\0'; + *begin_offset++ = '\0'; + *end_offset = '\0'; + + // mangled name is now in [begin_name, begin_offset) and caller + // offset in [begin_offset, end_offset). now apply + // __cxa_demangle(): + + int status; + char* ret = abi::__cxa_demangle(begin_name, + funcname, &funcnamesize, &status); + if (status == 0) { + funcname = ret; // use possibly realloc()-ed string + fprintf(out, " %s : %s+%s %s\n", + symbollist[i], funcname, begin_offset, ++end_offset); + } + else { + // demangling failed. Output function name as a C function with + // no arguments. + fprintf(out, " %s : %s()+%s %s\n", + symbollist[i], begin_name, begin_offset, ++end_offset); + } + } + else + { + // couldn't parse the line? print the whole line. + fprintf(out, " %s\n", symbollist[i]); + } + } + + free(funcname); + free(symbollist); +} + +#endif // _STACKTRACE_H_