From 5c3c6b63ba96c89e1482bbff83a7851281a63e49 Mon Sep 17 00:00:00 2001 From: Chocobo1 Date: Thu, 12 May 2022 11:06:05 +0800 Subject: [PATCH] Migrate to Boost.Stacktrace PR #17014. --- CMakeLists.txt | 12 -- src/app/CMakeLists.txt | 42 ++-- src/app/app.pri | 8 +- src/app/signalhandler.cpp | 16 +- src/app/stacktrace.cpp | 36 ++++ src/app/stacktrace.h | 149 ++++----------- src/app/stacktrace_win.h | 360 ----------------------------------- src/gui/stacktracedialog.cpp | 5 +- src/src.pro | 11 +- unixconf.pri | 1 - winconf.pri | 16 +- 11 files changed, 122 insertions(+), 534 deletions(-) create mode 100644 src/app/stacktrace.cpp delete mode 100644 src/app/stacktrace_win.h diff --git a/CMakeLists.txt b/CMakeLists.txt index de69e8c9a..4c6ffc889 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -37,18 +37,6 @@ if (CMAKE_SYSTEM_NAME STREQUAL "Linux") "Install systemd service file to a directory manually overridable with SYSTEMD_SERVICES_INSTALL_DIR" OFF "NOT GUI" OFF ) - if (STACKTRACE) - check_cxx_source_compiles( - "#include - int main(){return 0;}" - QBITTORRENT_HAS_EXECINFO_H - ) - if (NOT QBITTORRENT_HAS_EXECINFO_H) - message(FATAL_ERROR "execinfo.h header file not found.\n" - "Please either disable the STACKTRACE feature or use a libc that has this header file, such as glibc (GNU libc)." - ) - endif() - endif() elseif (MSVC) feature_option(MSVC_RUNTIME_DYNAMIC "Use MSVC dynamic runtime library (-MD) instead of static (-MT)" ON) endif() diff --git a/src/app/CMakeLists.txt b/src/app/CMakeLists.txt index 2bf2daae0..80830c80f 100644 --- a/src/app/CMakeLists.txt +++ b/src/app/CMakeLists.txt @@ -101,35 +101,45 @@ endif() # Additional feature dependent configuration # ----------------------------------------------------------------------------- # ----------------------------------------------------------------------------- +if (GUI) + target_link_libraries(qbt_app PRIVATE qbt_gui) + if ((CMAKE_SYSTEM_NAME STREQUAL "Windows") OR (CMAKE_SYSTEM_NAME STREQUAL "Darwin")) + qt_import_plugins(qbt_app INCLUDE Qt::QSvgIconPlugin Qt::QSvgPlugin) + endif() +endif() + if (STACKTRACE) target_compile_definitions(qbt_app PRIVATE STACKTRACE) - if (CMAKE_SYSTEM_NAME STREQUAL "Windows") - target_sources(qbt_app PRIVATE stacktrace_win.h) + target_sources(qbt_app PRIVATE + stacktrace.h + stacktrace.cpp + ) - # i686 arch on Windows requires frame pointer preservation + if (CMAKE_SYSTEM_NAME STREQUAL "Darwin") + target_compile_definitions(qbt_app PRIVATE BOOST_STACKTRACE_GNU_SOURCE_NOT_REQUIRED) + target_link_options(qbt_app PUBLIC -rdynamic) + elseif (CMAKE_SYSTEM_NAME STREQUAL "Linux") + target_link_libraries(qbt_app PUBLIC ${CMAKE_DL_LIBS}) + target_link_options(qbt_app PUBLIC -rdynamic) + elseif (CMAKE_SYSTEM_NAME STREQUAL "Windows") if (MSVC) target_compile_options(qbt_app PRIVATE /Zi) - target_link_options(qbt_app PUBLIC LINKER:/DEBUG) + target_link_options(qbt_app PUBLIC + /DEBUG + /PDBALTPATH:$ + ) + if (CMAKE_SIZEOF_VOID_P EQUAL 4) - target_compile_options(qbt_app PRIVATE /Oy) + target_compile_options(qbt_app PRIVATE /Oy-) endif() else() + target_link_options(qbt_app PUBLIC LINKER:--export-dynamic) + if (CMAKE_SIZEOF_VOID_P EQUAL 4) target_compile_options(qbt_app PRIVATE -fno-omit-frame-pointer) endif() endif() - - target_link_libraries(qbt_app PUBLIC dbghelp) - else() - target_sources(qbt_app PRIVATE stacktrace.h) - endif() -endif() - -if (GUI) - target_link_libraries(qbt_app PRIVATE qbt_gui) - if ((CMAKE_SYSTEM_NAME STREQUAL "Windows") OR (CMAKE_SYSTEM_NAME STREQUAL "Darwin")) - qt_import_plugins(qbt_app INCLUDE Qt::QSvgIconPlugin Qt::QSvgPlugin) endif() endif() diff --git a/src/app/app.pri b/src/app/app.pri index 5fa6e0473..bdec650d3 100644 --- a/src/app/app.pri +++ b/src/app/app.pri @@ -20,10 +20,6 @@ SOURCES += \ $$PWD/upgrade.cpp stacktrace { - unix { - HEADERS += $$PWD/stacktrace.h - } - win32 { - HEADERS += $$PWD/stacktrace_win.h - } + HEADERS += $$PWD/stacktrace.h + SOURCES += $$PWD/stacktrace.cpp } diff --git a/src/app/signalhandler.cpp b/src/app/signalhandler.cpp index a164e3e46..d478dd690 100644 --- a/src/app/signalhandler.cpp +++ b/src/app/signalhandler.cpp @@ -49,14 +49,11 @@ #include "base/version.h" #ifdef STACKTRACE -#ifdef Q_OS_UNIX #include "stacktrace.h" -#else -#include "stacktrace_win.h" -#ifndef DISABLE_GUI + +#if defined Q_OS_WIN && !defined DISABLE_GUI #include "gui/stacktracedialog.h" -#endif // DISABLE_GUI -#endif // Q_OS_UNIX +#endif #endif //STACKTRACE namespace @@ -113,14 +110,17 @@ namespace "Caught signal: "; const char *msgs[] = {msg, sigName, "\n"}; std::for_each(std::begin(msgs), std::end(msgs), safePrint); + #if !defined Q_OS_WIN - print_stacktrace(); // unsafe + safePrint("```\n"); + safePrint(getStacktrace().c_str()); + safePrint("```\n\n"); #endif #endif #if defined Q_OS_WIN && !defined DISABLE_GUI StacktraceDialog dlg; // unsafe - dlg.setText(QString::fromLatin1(sigName), straceWin::getBacktrace()); + dlg.setText(QString::fromLatin1(sigName), QString::fromStdString(getStacktrace())); dlg.exec(); #endif diff --git a/src/app/stacktrace.cpp b/src/app/stacktrace.cpp new file mode 100644 index 000000000..77f7e7cad --- /dev/null +++ b/src/app/stacktrace.cpp @@ -0,0 +1,36 @@ +/* + * Bittorrent Client using Qt and libtorrent. + * Copyright (C) 2022 Mike Tzou (Chocobo1) + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * In addition, as a special exception, the copyright holders give permission to + * link this program with the OpenSSL project's "OpenSSL" library (or with + * modified versions of it that use the same license as the "OpenSSL" library), + * and distribute the linked executables. You must obey the GNU General Public + * License in all respects for all of the code used other than "OpenSSL". If you + * modify file(s), you may extend this exception to your version of the file(s), + * but you are not obligated to do so. If you do not wish to do so, delete this + * exception statement from your version. + */ + +#include "stacktrace.h" + +#include + +std::string getStacktrace() +{ + return boost::stacktrace::to_string(boost::stacktrace::stacktrace()); +} diff --git a/src/app/stacktrace.h b/src/app/stacktrace.h index 1b332ecf5..e7aa5c8f3 100644 --- a/src/app/stacktrace.h +++ b/src/app/stacktrace.h @@ -1,116 +1,33 @@ -// 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 - -#include - -/** Print a demangled stack backtrace of the caller function to FILE* out. */ -static inline void print_stacktrace(FILE *out = stderr, const int max_frames = 63) -{ - fprintf(out, "Stack trace:\n"); - - // storage array for stack trace address data - std::vector addrlist(max_frames + 1); - - // retrieve current stack addresses - int addrlen = backtrace(addrlist.data(), addrlist.size()); - - 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.data(), addrlen); - - // allocate string which will be filled with the demangled function name - size_t funcnamesize = 256; - char *funcname = static_cast(malloc(funcnamesize)); - - int functionNamesFound = 0; - // 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); - } - ++functionNamesFound; - } - else - { - // couldn't parse the line? print the whole line. - fprintf(out, " %s\n", symbollist[i]); - } - } - - if (!functionNamesFound) - { - fprintf(out, "There were no function names found in the stack trace\n." - "Seems like debug symbols are not installed, and the stack trace is useless.\n"); - } - if (functionNamesFound < addrlen - 2) - { - fprintf(out, "Consider installing debug symbols for packages containing files with empty" - " function names (i.e. empty braces \"()\") to make your stack trace more useful\n"); - } - free(funcname); - free(symbollist); -} - -#endif // _STACKTRACE_H_ +/* + * Bittorrent Client using Qt and libtorrent. + * Copyright (C) 2022 Mike Tzou (Chocobo1) + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * In addition, as a special exception, the copyright holders give permission to + * link this program with the OpenSSL project's "OpenSSL" library (or with + * modified versions of it that use the same license as the "OpenSSL" library), + * and distribute the linked executables. You must obey the GNU General Public + * License in all respects for all of the code used other than "OpenSSL". If you + * modify file(s), you may extend this exception to your version of the file(s), + * but you are not obligated to do so. If you do not wish to do so, delete this + * exception statement from your version. + */ + +#pragma once + +#include + +std::string getStacktrace(); diff --git a/src/app/stacktrace_win.h b/src/app/stacktrace_win.h deleted file mode 100644 index 0280520f2..000000000 --- a/src/app/stacktrace_win.h +++ /dev/null @@ -1,360 +0,0 @@ -/*************************************************************************** -* Copyright (C) 2005-09 by the Quassel Project * -* devel@quassel-irc.org * -* * -* This program is free software; you can redistribute it and/or modify * -* it under the terms of the GNU General Public License as published by * -* the Free Software Foundation; either version 2 of the License, or * -* (at your option) version 3. * -* * -* This program is distributed in the hope that it will be useful, * -* but WITHOUT ANY WARRANTY; without even the implied warranty of * -* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * -* GNU General Public License for more details. * -* * -* You should have received a copy of the GNU General Public License * -* along with this program; if not, write to the * -* Free Software Foundation, Inc., * -* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * -***************************************************************************/ - -#pragma once - -#include -#include -#include - -#include -#include -#include -#ifdef __MINGW32__ -#include -#endif - -#include "base/global.h" - -namespace straceWin -{ - void loadHelpStackFrame(IMAGEHLP_STACK_FRAME&, const STACKFRAME64&); - BOOL CALLBACK EnumSymbolsCB(PSYMBOL_INFO, ULONG, PVOID); - BOOL CALLBACK EnumModulesCB(LPCSTR, DWORD64, PVOID); - const QString getBacktrace(); - struct EnumModulesContext; - // Also works for MinGW64 -#ifdef __MINGW32__ - void demangle(QString& str); -#endif - - QString getSourcePathAndLineNumber(HANDLE hProcess, DWORD64 addr); - bool makeRelativePath(const QString& dir, QString& file); -} - -#ifdef __MINGW32__ -void straceWin::demangle(QString& str) -{ - char const* inStr = qPrintable(u"_" + str); // Really need that underline or demangling will fail - int status = 0; - size_t outSz = 0; - char* demangled_name = abi::__cxa_demangle(inStr, 0, &outSz, &status); - if (status == 0) - { - str = QString::fromLocal8Bit(demangled_name); - if (outSz > 0) - free(demangled_name); - } -} -#endif - -void straceWin::loadHelpStackFrame(IMAGEHLP_STACK_FRAME& ihsf, const STACKFRAME64& stackFrame) -{ - ZeroMemory(&ihsf, sizeof(IMAGEHLP_STACK_FRAME)); - ihsf.InstructionOffset = stackFrame.AddrPC.Offset; - ihsf.FrameOffset = stackFrame.AddrFrame.Offset; -} - -BOOL CALLBACK straceWin::EnumSymbolsCB(PSYMBOL_INFO symInfo, ULONG size, PVOID user) -{ - Q_UNUSED(size) - auto params = static_cast(user); - if (symInfo->Flags & SYMFLAG_PARAMETER) - params->append(QString::fromUtf8(symInfo->Name)); - return TRUE; -} - - -struct straceWin::EnumModulesContext -{ - HANDLE hProcess; - QTextStream& stream; - EnumModulesContext(HANDLE hProcess, QTextStream& stream): hProcess(hProcess), stream(stream) {} -}; - -BOOL CALLBACK straceWin::EnumModulesCB(LPCSTR ModuleName, DWORD64 BaseOfDll, PVOID UserContext) -{ - Q_UNUSED(ModuleName) - IMAGEHLP_MODULE64 mod; - auto context = static_cast(UserContext); - mod.SizeOfStruct = sizeof(IMAGEHLP_MODULE64); - if(SymGetModuleInfo64(context->hProcess, BaseOfDll, &mod)) - { - QString moduleBase = u"0x%1"_qs.arg(BaseOfDll, 16, 16, QChar(u'0')); - QString line = u"%1 %2 Image: %3"_qs - .arg(QString::fromUtf8(mod.ModuleName), -25) - .arg(moduleBase, -13) - .arg(QString::fromUtf8(mod.LoadedImageName)); - context->stream << line << '\n'; - - const auto pdbName = QString::fromUtf8(mod.LoadedPdbName); - if(!pdbName.isEmpty()) - { - QString line2 = u"%1 %2"_qs - .arg(u""_qs, 35) - .arg(pdbName); - context->stream << line2 << '\n'; - } - } - return TRUE; -} - - -/** -* Cuts off leading 'dir' path from 'file' path, otherwise leaves it unchanged -* returns true if 'dir' is an ancestor of 'file', otherwise - false -*/ -bool straceWin::makeRelativePath(const QString &dir, QString &file) -{ - QString d = QDir::toNativeSeparators(QDir(dir).absolutePath()); - QString f = QDir::toNativeSeparators(QFileInfo(file).absoluteFilePath()); - - // append separator at the end of dir - QChar separator = QDir::separator(); - if (!d.isEmpty() && (d[d.length() - 1] != separator)) - d += separator; - - if (f.startsWith(d, Qt::CaseInsensitive)) - { - f.remove(0, d.length()); - file.swap(f); - - return true; - } - - return false; -} - -QString straceWin::getSourcePathAndLineNumber(HANDLE hProcess, DWORD64 addr) -{ - IMAGEHLP_LINE64 line {}; - line.SizeOfStruct = sizeof(IMAGEHLP_LINE64); - DWORD dwDisplacement = 0; - - if (SymGetLineFromAddr64(hProcess, addr, &dwDisplacement, &line)) - { - auto path = QString::fromUtf8(line.FileName); - -#if defined STACKTRACE_WIN_PROJECT_PATH || defined STACKTRACE_WIN_MAKEFILE_PATH - -#define STACKTRACE_WIN_QUOTE(x) #x -#define STACKTRACE_WIN_STRING(x) STACKTRACE_WIN_QUOTE(x) - - //prune leading project directory path or build target directory path - - bool success = false; -#ifdef STACKTRACE_WIN_PROJECT_PATH - const auto projectPath = QStringLiteral(STACKTRACE_WIN_STRING(STACKTRACE_WIN_PROJECT_PATH)); - success = makeRelativePath(projectPath, path); -#endif - -#ifdef STACKTRACE_WIN_MAKEFILE_PATH - if (!success) - { - const auto targetPath = QStringLiteral(STACKTRACE_WIN_STRING(STACKTRACE_WIN_MAKEFILE_PATH)); - makeRelativePath(targetPath, path); - } -#endif -#endif - return u"%1 : %2"_qs.arg(path).arg(line.LineNumber); - } - - return QString(); -} - - -#if defined( _M_IX86 ) && defined(Q_CC_MSVC) -// Disable global optimization and ignore /GS waning caused by -// inline assembly. -// not needed with mingw cause we can tell mingw which registers we use -#pragma optimize("g", off) -#pragma warning(push) -#pragma warning(disable : 4748) -#endif -const QString straceWin::getBacktrace() -{ - DWORD MachineType; - CONTEXT Context; - STACKFRAME64 StackFrame; - -#ifdef _M_IX86 - ZeroMemory(&Context, sizeof(CONTEXT)); - Context.ContextFlags = CONTEXT_CONTROL; - - -#ifdef __MINGW32__ - asm ("Label:\n\t" - "movl %%ebp,%0;\n\t" - "movl %%esp,%1;\n\t" - "movl $Label,%%eax;\n\t" - "movl %%eax,%2;\n\t" - : "=r" (Context.Ebp),"=r" (Context.Esp),"=r" (Context.Eip) - : //no input - : "eax"); -#else - _asm - { - Label: - mov [Context.Ebp], ebp; - mov [Context.Esp], esp; - mov eax, [Label]; - mov [Context.Eip], eax; - } -#endif -#else - RtlCaptureContext(&Context); -#endif - - ZeroMemory(&StackFrame, sizeof(STACKFRAME64)); -#ifdef _M_IX86 - MachineType = IMAGE_FILE_MACHINE_I386; - StackFrame.AddrPC.Offset = Context.Eip; - StackFrame.AddrPC.Mode = AddrModeFlat; - StackFrame.AddrFrame.Offset = Context.Ebp; - StackFrame.AddrFrame.Mode = AddrModeFlat; - StackFrame.AddrStack.Offset = Context.Esp; - StackFrame.AddrStack.Mode = AddrModeFlat; -#elif _M_X64 - MachineType = IMAGE_FILE_MACHINE_AMD64; - StackFrame.AddrPC.Offset = Context.Rip; - StackFrame.AddrPC.Mode = AddrModeFlat; - StackFrame.AddrFrame.Offset = Context.Rsp; - StackFrame.AddrFrame.Mode = AddrModeFlat; - StackFrame.AddrStack.Offset = Context.Rsp; - StackFrame.AddrStack.Mode = AddrModeFlat; -#elif _M_IA64 - MachineType = IMAGE_FILE_MACHINE_IA64; - StackFrame.AddrPC.Offset = Context.StIIP; - StackFrame.AddrPC.Mode = AddrModeFlat; - StackFrame.AddrFrame.Offset = Context.IntSp; - StackFrame.AddrFrame.Mode = AddrModeFlat; - StackFrame.AddrBStore.Offset = Context.RsBSP; - StackFrame.AddrBStore.Mode = AddrModeFlat; - StackFrame.AddrStack.Offset = Context.IntSp; - StackFrame.AddrStack.Mode = AddrModeFlat; -#else -#error "Unsupported platform" -#endif - - QString log; - QTextStream logStream(&log); - logStream << "```\n"; - - const std::wstring appPath = QCoreApplication::applicationDirPath().toStdWString(); - HANDLE hProcess = GetCurrentProcess(); - HANDLE hThread = GetCurrentThread(); - SymInitializeW(hProcess, appPath.c_str(), TRUE); - - DWORD64 dwDisplacement; - - ULONG64 buffer[(sizeof(SYMBOL_INFO) + - MAX_SYM_NAME * sizeof(TCHAR) + - sizeof(ULONG64) - 1) / sizeof(ULONG64)]; - auto pSymbol = reinterpret_cast(buffer); - pSymbol->SizeOfStruct = sizeof(SYMBOL_INFO); - pSymbol->MaxNameLen = MAX_SYM_NAME; - - IMAGEHLP_MODULE64 mod; - mod.SizeOfStruct = sizeof(IMAGEHLP_MODULE64); - - IMAGEHLP_STACK_FRAME ihsf; - ZeroMemory(&ihsf, sizeof(IMAGEHLP_STACK_FRAME)); - - int i = 0; - - while(StackWalk64(MachineType, hProcess, hThread, &StackFrame, &Context, NULL, NULL, NULL, NULL)) - { - if(i == 128) - break; - - loadHelpStackFrame(ihsf, StackFrame); - if(StackFrame.AddrPC.Offset != 0) - { // Valid frame. - - auto fileName = u"???"_qs; - if(SymGetModuleInfo64(hProcess, ihsf.InstructionOffset, &mod)) - { - fileName = QString::fromUtf8(mod.ImageName); - int slashPos = fileName.lastIndexOf(u'\\'); - if(slashPos != -1) - fileName = fileName.mid(slashPos + 1); - } - QString funcName; - QString sourceFile; - if(SymFromAddr(hProcess, ihsf.InstructionOffset, &dwDisplacement, pSymbol)) - { - funcName = QString::fromUtf8(pSymbol->Name); -#ifdef __MINGW32__ - demangle(funcName); -#endif - - // now ihsf.InstructionOffset points to the instruction that follows CALL instruction - // decrease the query address by one byte to point somewhere in the CALL instruction byte sequence - sourceFile = getSourcePathAndLineNumber(hProcess, ihsf.InstructionOffset - 1); - } - else - { - funcName = u"0x%1"_qs.arg(ihsf.InstructionOffset, 8, 16, QChar(u'0')); - } - SymSetContext(hProcess, &ihsf, NULL); -#ifndef __MINGW32__ - QStringList params; - SymEnumSymbols(hProcess, 0, NULL, EnumSymbolsCB, (PVOID)¶ms); -#endif - - QString insOffset = u"0x%1"_qs.arg(ihsf.InstructionOffset, 16, 16, QChar(u'0')); - auto formatLine = u"#%1 %2 %3 %4"_qs; -#ifndef __MINGW32__ - formatLine += u"(%5)"_qs; -#endif - QString debugLine = formatLine - .arg(i, 3, 10) - .arg(fileName, -20) - .arg(insOffset, -11) - .arg(funcName) -#ifndef __MINGW32__ - .arg(params.join(u", ")); - - if (!sourceFile.isEmpty()) - debugLine += u"[ %1 ]"_qs.arg(sourceFile); -#else - ; -#endif - logStream << debugLine << '\n'; - i++; - } - else - { - break; // we're at the end. - } - } - - //logStream << "\n\nList of linked Modules:\n"; - //EnumModulesContext modulesContext(hProcess, logStream); - //SymEnumerateModules64(hProcess, EnumModulesCB, (PVOID)&modulesContext); - SymCleanup(hProcess); - - logStream << "```"; - return log; -} -#if defined(_M_IX86) && defined(Q_CC_MSVC) -#pragma warning(pop) -#pragma optimize("g", on) -#endif diff --git a/src/gui/stacktracedialog.cpp b/src/gui/stacktracedialog.cpp index 7fa44803b..05b4218fb 100644 --- a/src/gui/stacktracedialog.cpp +++ b/src/gui/stacktracedialog.cpp @@ -49,7 +49,8 @@ StacktraceDialog::~StacktraceDialog() void StacktraceDialog::setText(const QString &signalName, const QString &stacktrace) { - // try to call Qt function as less as possible + // try not to call signal-unsafe functions + const QString htmlStr = QStringLiteral( "

" "qBittorrent has crashed" @@ -70,7 +71,7 @@ void StacktraceDialog::setText(const QString &signalName, const QString &stacktr "OS version: %6

" "Caught signal: %7" "

" - "
%8
" + "
```\n%8\n```
" "



") .arg(QString::number(QT_POINTER_SIZE * 8) , Utils::Misc::libtorrentVersionString() diff --git a/src/src.pro b/src/src.pro index 48114fe17..3291793f6 100644 --- a/src/src.pro +++ b/src/src.pro @@ -37,9 +37,14 @@ nowebui { stacktrace { DEFINES += STACKTRACE - win32 { - DEFINES += STACKTRACE_WIN_PROJECT_PATH=$$PWD - DEFINES += STACKTRACE_WIN_MAKEFILE_PATH=$$OUT_PWD + + macx { + DEFINES += BOOST_STACKTRACE_GNU_SOURCE_NOT_REQUIRED + QMAKE_LFLAGS += -rdynamic + } + unix { + LIBS += -ldl + QMAKE_LFLAGS += -rdynamic } } diff --git a/unixconf.pri b/unixconf.pri index b42606946..fcc757ce0 100644 --- a/unixconf.pri +++ b/unixconf.pri @@ -11,7 +11,6 @@ else { !nogui:dbus: QT += dbus QMAKE_CXXFLAGS += -Wall -Wextra -Wpedantic -Wformat-security -!haiku: QMAKE_LFLAGS_APP += -rdynamic # Man page nogui { diff --git a/winconf.pri b/winconf.pri index d6be8f045..4310af0ab 100644 --- a/winconf.pri +++ b/winconf.pri @@ -60,24 +60,20 @@ else { # Stack trace support can be enabled in 'conf.pri' stacktrace { win32-g++*|win32-clang-g++* { + QMAKE_LFLAGS += -Wl,--export-dynamic + contains(QMAKE_HOST.arch, x86) { # i686 arch requires frame pointer preservation QMAKE_CXXFLAGS += -fno-omit-frame-pointer } - - QMAKE_LFLAGS += -Wl,--export-all-symbols - - LIBS += libdbghelp } else:win32-msvc* { + QMAKE_CXXFLAGS += /Zi + QMAKE_LFLAGS += "/DEBUG /PDBALTPATH:%_PDB%" + contains(QMAKE_HOST.arch, x86) { # i686 arch requires frame pointer preservation - QMAKE_CXXFLAGS += -Oy- + QMAKE_CXXFLAGS += /Oy- } - - QMAKE_CXXFLAGS *= -Zi - QMAKE_LFLAGS *= "/DEBUG" - - LIBS += dbghelp.lib } }