For Linux GCC builds, print stack trace on crash.

This commit is contained in:
Craig Drummond
2018-04-02 23:04:18 +01:00
committed by Craig Drummond
parent 286a3da71d
commit c8d7f2ad84
2 changed files with 82 additions and 0 deletions

View File

@@ -80,6 +80,7 @@
60. Fix small side-bar when at top, or bottom.
61. Try to make UI responseive to available width. Hide toolbar and statusbar
items in insufficient space. Switch view type when narrow.
62. For Linux GCC builds, print stack trace on crash.
2.2.0
-----

View File

@@ -255,8 +255,89 @@ static void installDebugMessageHandler(const QString &cmdLine)
qInstallMessageHandler(cantataQtMsgHandler);
}
#if defined Q_OS_LINUX && defined __GNUC__
#include <execinfo.h>
#include <unistd.h>
#include <signal.h>
#include <cxxabi.h>
static void sigHandler(int i)
{
// Adapted from: https://panthema.net/2008/0901-stacktrace-demangled/
// stacktrace.h (c) 2008, Timo Bingmann from http://idlebox.net/
// published under the WTFPL v2.0
static const int constMaxFuncNameLen = 256;
static const int constNumLevels = 15;
void *addrlist[constNumLevels+1];
fprintf(stderr, "Unfortunately Cantata has crashed. Please report a bug at \n"
"https://github.com/CDrummond/cantata/issues/ and include the following stack trace:\n\n");
// retrieve current stack addresses
int addrlen = backtrace(addrlist, sizeof(addrlist) / sizeof(void*));
if (!addrlen) {
fprintf(stderr, "Failed to produce stack trace!\n");
_exit(0);
}
char ** symbolList = backtrace_symbols(addrlist, addrlen);
char funcName[constMaxFuncNameLen];
// iterate over the returned symbol lines. skip the first, it is the
// address of this function.
for (int i = 1; i < addrlen; i++) {
char *beginName = nullptr;
char *beginOffset = nullptr;
char *endOffset = nullptr;
// find parentheses and +address offset surrounding the mangled name:
// ./module(function+0x15c) [0x8048a6d]
for (char *p = symbolList[i]; *p; ++p) {
if (*p == '(') {
beginName = p;
} else if (*p == '+') {
beginOffset = p;
} else if (*p == ')' && beginOffset) {
endOffset = p;
break;
}
}
if (beginName && beginOffset && endOffset && beginName < beginOffset) {
*beginName++ = '\0';
*beginOffset++ = '\0';
*endOffset = '\0';
// mangled name is now in [begin_name, begin_offset) and caller
// offset in [begin_offset, end_offset). now apply
// __cxa_demangle():
int status = 0;
size_t nameLen = constMaxFuncNameLen;
char * ret = abi::__cxa_demangle(beginName, funcName, &nameLen, &status);
if (!status) {
fprintf(stderr, " %s : %s+%s\n", symbolList[i], ret, beginOffset);
} else {
// demangling failed. Output function name as a C function with
// no arguments.
fprintf(stderr, " %s : %s()+%s\n", symbolList[i], beginName, beginOffset);
}
} else {
// couldn't parse the line? print the whole line.
fprintf(stderr, " %s\n", symbolList[i]);
}
}
free(symbolList);
_exit(1);
}
#endif
int main(int argc, char *argv[])
{
#if defined Q_OS_LINUX && defined __GNUC__
signal(SIGSEGV, sigHandler);
#endif
QThread::currentThread()->setObjectName("GUI");
QCoreApplication::setApplicationName(PACKAGE_NAME);
QCoreApplication::setOrganizationName(ORGANIZATION_NAME);