For Linux GCC builds, print stack trace on crash.
This commit is contained in:
committed by
Craig Drummond
parent
286a3da71d
commit
c8d7f2ad84
@@ -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
|
||||
-----
|
||||
|
||||
81
gui/main.cpp
81
gui/main.cpp
@@ -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);
|
||||
|
||||
Reference in New Issue
Block a user