Browse Source

Migrate to Boost.Stacktrace

PR #17014.
adaptive-webui-19844
Chocobo1 2 years ago committed by GitHub
parent
commit
5c3c6b63ba
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 12
      CMakeLists.txt
  2. 42
      src/app/CMakeLists.txt
  3. 8
      src/app/app.pri
  4. 16
      src/app/signalhandler.cpp
  5. 36
      src/app/stacktrace.cpp
  6. 149
      src/app/stacktrace.h
  7. 360
      src/app/stacktrace_win.h
  8. 5
      src/gui/stacktracedialog.cpp
  9. 11
      src/src.pro
  10. 1
      unixconf.pri
  11. 16
      winconf.pri

12
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" "Install systemd service file to a directory manually overridable with SYSTEMD_SERVICES_INSTALL_DIR"
OFF "NOT GUI" OFF OFF "NOT GUI" OFF
) )
if (STACKTRACE)
check_cxx_source_compiles(
"#include <execinfo.h>
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) elseif (MSVC)
feature_option(MSVC_RUNTIME_DYNAMIC "Use MSVC dynamic runtime library (-MD) instead of static (-MT)" ON) feature_option(MSVC_RUNTIME_DYNAMIC "Use MSVC dynamic runtime library (-MD) instead of static (-MT)" ON)
endif() endif()

42
src/app/CMakeLists.txt

@ -101,35 +101,45 @@ endif()
# Additional feature dependent configuration # 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) if (STACKTRACE)
target_compile_definitions(qbt_app PRIVATE STACKTRACE) target_compile_definitions(qbt_app PRIVATE STACKTRACE)
if (CMAKE_SYSTEM_NAME STREQUAL "Windows") target_sources(qbt_app PRIVATE
target_sources(qbt_app PRIVATE stacktrace_win.h) 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) if (MSVC)
target_compile_options(qbt_app PRIVATE /Zi) target_compile_options(qbt_app PRIVATE /Zi)
target_link_options(qbt_app PUBLIC LINKER:/DEBUG) target_link_options(qbt_app PUBLIC
/DEBUG
/PDBALTPATH:$<TARGET_PDB_FILE_NAME:qbt_app>
)
if (CMAKE_SIZEOF_VOID_P EQUAL 4) if (CMAKE_SIZEOF_VOID_P EQUAL 4)
target_compile_options(qbt_app PRIVATE /Oy) target_compile_options(qbt_app PRIVATE /Oy-)
endif() endif()
else() else()
target_link_options(qbt_app PUBLIC LINKER:--export-dynamic)
if (CMAKE_SIZEOF_VOID_P EQUAL 4) if (CMAKE_SIZEOF_VOID_P EQUAL 4)
target_compile_options(qbt_app PRIVATE -fno-omit-frame-pointer) target_compile_options(qbt_app PRIVATE -fno-omit-frame-pointer)
endif() endif()
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()
endif() endif()

8
src/app/app.pri

@ -20,10 +20,6 @@ SOURCES += \
$$PWD/upgrade.cpp $$PWD/upgrade.cpp
stacktrace { stacktrace {
unix { HEADERS += $$PWD/stacktrace.h
HEADERS += $$PWD/stacktrace.h SOURCES += $$PWD/stacktrace.cpp
}
win32 {
HEADERS += $$PWD/stacktrace_win.h
}
} }

16
src/app/signalhandler.cpp

@ -49,14 +49,11 @@
#include "base/version.h" #include "base/version.h"
#ifdef STACKTRACE #ifdef STACKTRACE
#ifdef Q_OS_UNIX
#include "stacktrace.h" #include "stacktrace.h"
#else
#include "stacktrace_win.h" #if defined Q_OS_WIN && !defined DISABLE_GUI
#ifndef DISABLE_GUI
#include "gui/stacktracedialog.h" #include "gui/stacktracedialog.h"
#endif // DISABLE_GUI #endif
#endif // Q_OS_UNIX
#endif //STACKTRACE #endif //STACKTRACE
namespace namespace
@ -113,14 +110,17 @@ namespace
"Caught signal: "; "Caught signal: ";
const char *msgs[] = {msg, sigName, "\n"}; const char *msgs[] = {msg, sigName, "\n"};
std::for_each(std::begin(msgs), std::end(msgs), safePrint); std::for_each(std::begin(msgs), std::end(msgs), safePrint);
#if !defined Q_OS_WIN #if !defined Q_OS_WIN
print_stacktrace(); // unsafe safePrint("```\n");
safePrint(getStacktrace().c_str());
safePrint("```\n\n");
#endif #endif
#endif #endif
#if defined Q_OS_WIN && !defined DISABLE_GUI #if defined Q_OS_WIN && !defined DISABLE_GUI
StacktraceDialog dlg; // unsafe StacktraceDialog dlg; // unsafe
dlg.setText(QString::fromLatin1(sigName), straceWin::getBacktrace()); dlg.setText(QString::fromLatin1(sigName), QString::fromStdString(getStacktrace()));
dlg.exec(); dlg.exec();
#endif #endif

36
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 <boost/stacktrace.hpp>
std::string getStacktrace()
{
return boost::stacktrace::to_string(boost::stacktrace::stacktrace());
}

149
src/app/stacktrace.h

@ -1,116 +1,33 @@
// stacktrace.h (c) 2008, Timo Bingmann from http://idlebox.net/ /*
// published under the WTFPL v2.0 * Bittorrent Client using Qt and libtorrent.
* Copyright (C) 2022 Mike Tzou (Chocobo1)
#ifndef _STACKTRACE_H_ *
#define _STACKTRACE_H_ * This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
#include <stdio.h> * as published by the Free Software Foundation; either version 2
#include <stdlib.h> * of the License, or (at your option) any later version.
#include <execinfo.h> *
#include <cxxabi.h> * This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
#include <vector> * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
/** 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) * You should have received a copy of the GNU General Public License
{ * along with this program; if not, write to the Free Software
fprintf(out, "Stack trace:\n"); * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
// storage array for stack trace address data * In addition, as a special exception, the copyright holders give permission to
std::vector<void *> addrlist(max_frames + 1); * 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),
// retrieve current stack addresses * and distribute the linked executables. You must obey the GNU General Public
int addrlen = backtrace(addrlist.data(), addrlist.size()); * 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),
if (addrlen == 0) * but you are not obligated to do so. If you do not wish to do so, delete this
{ * exception statement from your version.
fprintf(out, " <empty, possibly corrupt>\n"); */
return;
} #pragma once
// resolve addresses into strings containing "filename(function+address)", #include <string>
// this array must be free()-ed
char * *symbollist = backtrace_symbols(addrlist.data(), addrlen); std::string getStacktrace();
// allocate string which will be filled with the demangled function name
size_t funcnamesize = 256;
char *funcname = static_cast<char *>(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_

360
src/app/stacktrace_win.h

@ -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 <windows.h>
#include <dbghelp.h>
#include <stdio.h>
#include <QCoreApplication>
#include <QDir>
#include <QTextStream>
#ifdef __MINGW32__
#include <cxxabi.h>
#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<QStringList *>(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<EnumModulesContext *>(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<PSYMBOL_INFO>(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)&params);
#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

5
src/gui/stacktracedialog.cpp

@ -49,7 +49,8 @@ StacktraceDialog::~StacktraceDialog()
void StacktraceDialog::setText(const QString &signalName, const QString &stacktrace) 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( const QString htmlStr = QStringLiteral(
"<p align=center><b><font size=7 color=red>" "<p align=center><b><font size=7 color=red>"
"qBittorrent has crashed" "qBittorrent has crashed"
@ -70,7 +71,7 @@ void StacktraceDialog::setText(const QString &signalName, const QString &stacktr
"OS version: %6<br/><br/>" "OS version: %6<br/><br/>"
"Caught signal: %7" "Caught signal: %7"
"</font></p>" "</font></p>"
"<pre><code>%8</code></pre>" "<pre><code>```\n%8\n```</code></pre>"
"<br/><hr><br/><br/>") "<br/><hr><br/><br/>")
.arg(QString::number(QT_POINTER_SIZE * 8) .arg(QString::number(QT_POINTER_SIZE * 8)
, Utils::Misc::libtorrentVersionString() , Utils::Misc::libtorrentVersionString()

11
src/src.pro

@ -37,9 +37,14 @@ nowebui {
stacktrace { stacktrace {
DEFINES += STACKTRACE DEFINES += STACKTRACE
win32 {
DEFINES += STACKTRACE_WIN_PROJECT_PATH=$$PWD macx {
DEFINES += STACKTRACE_WIN_MAKEFILE_PATH=$$OUT_PWD DEFINES += BOOST_STACKTRACE_GNU_SOURCE_NOT_REQUIRED
QMAKE_LFLAGS += -rdynamic
}
unix {
LIBS += -ldl
QMAKE_LFLAGS += -rdynamic
} }
} }

1
unixconf.pri

@ -11,7 +11,6 @@ else {
!nogui:dbus: QT += dbus !nogui:dbus: QT += dbus
QMAKE_CXXFLAGS += -Wall -Wextra -Wpedantic -Wformat-security QMAKE_CXXFLAGS += -Wall -Wextra -Wpedantic -Wformat-security
!haiku: QMAKE_LFLAGS_APP += -rdynamic
# Man page # Man page
nogui { nogui {

16
winconf.pri

@ -60,24 +60,20 @@ else {
# Stack trace support can be enabled in 'conf.pri' # Stack trace support can be enabled in 'conf.pri'
stacktrace { stacktrace {
win32-g++*|win32-clang-g++* { win32-g++*|win32-clang-g++* {
QMAKE_LFLAGS += -Wl,--export-dynamic
contains(QMAKE_HOST.arch, x86) { contains(QMAKE_HOST.arch, x86) {
# i686 arch requires frame pointer preservation # i686 arch requires frame pointer preservation
QMAKE_CXXFLAGS += -fno-omit-frame-pointer QMAKE_CXXFLAGS += -fno-omit-frame-pointer
} }
QMAKE_LFLAGS += -Wl,--export-all-symbols
LIBS += libdbghelp
} }
else:win32-msvc* { else:win32-msvc* {
QMAKE_CXXFLAGS += /Zi
QMAKE_LFLAGS += "/DEBUG /PDBALTPATH:%_PDB%"
contains(QMAKE_HOST.arch, x86) { contains(QMAKE_HOST.arch, x86) {
# i686 arch requires frame pointer preservation # i686 arch requires frame pointer preservation
QMAKE_CXXFLAGS += -Oy- QMAKE_CXXFLAGS += /Oy-
} }
QMAKE_CXXFLAGS *= -Zi
QMAKE_LFLAGS *= "/DEBUG"
LIBS += dbghelp.lib
} }
} }

Loading…
Cancel
Save