mirror of
https://github.com/d47081/qBittorrent.git
synced 2025-03-13 05:41:17 +00:00
parent
e698c09298
commit
5c3c6b63ba
@ -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 <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)
|
||||
feature_option(MSVC_RUNTIME_DYNAMIC "Use MSVC dynamic runtime library (-MD) instead of static (-MT)" ON)
|
||||
endif()
|
||||
|
@ -101,31 +101,6 @@ endif()
|
||||
# Additional feature dependent configuration
|
||||
# -----------------------------------------------------------------------------
|
||||
# -----------------------------------------------------------------------------
|
||||
if (STACKTRACE)
|
||||
target_compile_definitions(qbt_app PRIVATE STACKTRACE)
|
||||
|
||||
if (CMAKE_SYSTEM_NAME STREQUAL "Windows")
|
||||
target_sources(qbt_app PRIVATE stacktrace_win.h)
|
||||
|
||||
# i686 arch on Windows requires frame pointer preservation
|
||||
if (MSVC)
|
||||
target_compile_options(qbt_app PRIVATE /Zi)
|
||||
target_link_options(qbt_app PUBLIC LINKER:/DEBUG)
|
||||
if (CMAKE_SIZEOF_VOID_P EQUAL 4)
|
||||
target_compile_options(qbt_app PRIVATE /Oy)
|
||||
endif()
|
||||
else()
|
||||
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"))
|
||||
@ -133,6 +108,41 @@ if (GUI)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
if (STACKTRACE)
|
||||
target_compile_definitions(qbt_app PRIVATE STACKTRACE)
|
||||
|
||||
target_sources(qbt_app PRIVATE
|
||||
stacktrace.h
|
||||
stacktrace.cpp
|
||||
)
|
||||
|
||||
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
|
||||
/DEBUG
|
||||
/PDBALTPATH:$<TARGET_PDB_FILE_NAME:qbt_app>
|
||||
)
|
||||
|
||||
if (CMAKE_SIZEOF_VOID_P EQUAL 4)
|
||||
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()
|
||||
endif()
|
||||
endif()
|
||||
|
||||
if (WEBUI)
|
||||
target_sources(qbt_app PRIVATE
|
||||
${QBT_WEBUI_QM_FILES}
|
||||
|
@ -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
|
||||
}
|
||||
|
@ -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
|
||||
|
||||
|
36
src/app/stacktrace.cpp
Normal file
36
src/app/stacktrace.cpp
Normal file
@ -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());
|
||||
}
|
@ -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)
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#ifndef _STACKTRACE_H_
|
||||
#define _STACKTRACE_H_
|
||||
#pragma once
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <execinfo.h>
|
||||
#include <cxxabi.h>
|
||||
#include <string>
|
||||
|
||||
#include <vector>
|
||||
|
||||
/** 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<void *> addrlist(max_frames + 1);
|
||||
|
||||
// retrieve current stack addresses
|
||||
int addrlen = backtrace(addrlist.data(), addrlist.size());
|
||||
|
||||
if (addrlen == 0)
|
||||
{
|
||||
fprintf(out, " <empty, possibly corrupt>\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<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_
|
||||
std::string getStacktrace();
|
||||
|
@ -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)¶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
|
@ -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(
|
||||
"<p align=center><b><font size=7 color=red>"
|
||||
"qBittorrent has crashed"
|
||||
@ -70,7 +71,7 @@ void StacktraceDialog::setText(const QString &signalName, const QString &stacktr
|
||||
"OS version: %6<br/><br/>"
|
||||
"Caught signal: %7"
|
||||
"</font></p>"
|
||||
"<pre><code>%8</code></pre>"
|
||||
"<pre><code>```\n%8\n```</code></pre>"
|
||||
"<br/><hr><br/><br/>")
|
||||
.arg(QString::number(QT_POINTER_SIZE * 8)
|
||||
, Utils::Misc::libtorrentVersionString()
|
||||
|
11
src/src.pro
11
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
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -11,7 +11,6 @@ else {
|
||||
!nogui:dbus: QT += dbus
|
||||
|
||||
QMAKE_CXXFLAGS += -Wall -Wextra -Wpedantic -Wformat-security
|
||||
!haiku: QMAKE_LFLAGS_APP += -rdynamic
|
||||
|
||||
# Man page
|
||||
nogui {
|
||||
|
16
winconf.pri
16
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
|
||||
}
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user