mirror of
https://github.com/qbittorrent/qBittorrent
synced 2025-07-31 03:50:20 -07:00
Merge pull request #2214 from Gelmir/trace
Fix backtrace functionality under MinGW
This commit is contained in:
commit
6c0b74b94b
3 changed files with 253 additions and 199 deletions
|
@ -1,66 +1,94 @@
|
||||||
/***************************************************************************
|
/***************************************************************************
|
||||||
* Copyright (C) 2005-09 by the Quassel Project *
|
* Copyright (C) 2005-09 by the Quassel Project *
|
||||||
* devel@quassel-irc.org *
|
* devel@quassel-irc.org *
|
||||||
* *
|
* *
|
||||||
* This program is free software; you can redistribute it and/or modify *
|
* 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 *
|
* it under the terms of the GNU General Public License as published by *
|
||||||
* the Free Software Foundation; either version 2 of the License, or *
|
* the Free Software Foundation; either version 2 of the License, or *
|
||||||
* (at your option) version 3. *
|
* (at your option) version 3. *
|
||||||
* *
|
* *
|
||||||
* This program is distributed in the hope that it will be useful, *
|
* This program is distributed in the hope that it will be useful, *
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
|
||||||
* GNU General Public License for more details. *
|
* GNU General Public License for more details. *
|
||||||
* *
|
* *
|
||||||
* You should have received a copy of the GNU General Public License *
|
* You should have received a copy of the GNU General Public License *
|
||||||
* along with this program; if not, write to the *
|
* along with this program; if not, write to the *
|
||||||
* Free Software Foundation, Inc., *
|
* Free Software Foundation, Inc., *
|
||||||
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
|
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
|
||||||
***************************************************************************/
|
***************************************************************************/
|
||||||
|
|
||||||
#include <windows.h>
|
#include <windows.h>
|
||||||
#include <dbghelp.h>
|
#include <dbghelp.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
|
|
||||||
#include <QTextStream>
|
#include <QTextStream>
|
||||||
|
#ifdef __MINGW32__
|
||||||
|
#include <cxxabi.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
namespace straceWin{
|
namespace straceWin
|
||||||
|
{
|
||||||
void loadHelpStackFrame(IMAGEHLP_STACK_FRAME&, const STACKFRAME64&);
|
void loadHelpStackFrame(IMAGEHLP_STACK_FRAME&, const STACKFRAME64&);
|
||||||
BOOL CALLBACK EnumSymbolsCB(PSYMBOL_INFO, ULONG, PVOID);
|
BOOL CALLBACK EnumSymbolsCB(PSYMBOL_INFO, ULONG, PVOID);
|
||||||
BOOL CALLBACK EnumModulesCB(LPCSTR, DWORD64, PVOID);
|
BOOL CALLBACK EnumModulesCB(LPCSTR, DWORD64, PVOID);
|
||||||
const QString getBacktrace();
|
const QString getBacktrace();
|
||||||
struct EnumModulesContext;
|
struct EnumModulesContext;
|
||||||
|
// Also works for MinGW64
|
||||||
|
#ifdef __MINGW32__
|
||||||
|
void demangle(QString& str);
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
void straceWin::loadHelpStackFrame(IMAGEHLP_STACK_FRAME &ihsf, const STACKFRAME64 &stackFrame) {
|
#ifdef __MINGW32__
|
||||||
|
void straceWin::demangle(QString& str)
|
||||||
|
{
|
||||||
|
char const* inStr = qPrintable("_" + 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));
|
ZeroMemory(&ihsf, sizeof(IMAGEHLP_STACK_FRAME));
|
||||||
ihsf.InstructionOffset = stackFrame.AddrPC.Offset;
|
ihsf.InstructionOffset = stackFrame.AddrPC.Offset;
|
||||||
ihsf.FrameOffset = stackFrame.AddrFrame.Offset;
|
ihsf.FrameOffset = stackFrame.AddrFrame.Offset;
|
||||||
}
|
}
|
||||||
|
|
||||||
BOOL CALLBACK straceWin::EnumSymbolsCB(PSYMBOL_INFO symInfo, ULONG size, PVOID user) {
|
BOOL CALLBACK straceWin::EnumSymbolsCB(PSYMBOL_INFO symInfo, ULONG size, PVOID user)
|
||||||
QStringList *params = (QStringList *)user;
|
{
|
||||||
if(symInfo->Flags & SYMFLAG_PARAMETER) {
|
Q_UNUSED(size)
|
||||||
|
QStringList* params = (QStringList*)user;
|
||||||
|
if (symInfo->Flags & SYMFLAG_PARAMETER)
|
||||||
params->append(symInfo->Name);
|
params->append(symInfo->Name);
|
||||||
}
|
|
||||||
return TRUE;
|
return TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
struct straceWin::EnumModulesContext {
|
struct straceWin::EnumModulesContext
|
||||||
|
{
|
||||||
HANDLE hProcess;
|
HANDLE hProcess;
|
||||||
QTextStream &stream;
|
QTextStream& stream;
|
||||||
EnumModulesContext(HANDLE hProcess, QTextStream &stream) : hProcess(hProcess), stream(stream) {}
|
EnumModulesContext(HANDLE hProcess, QTextStream& stream): hProcess(hProcess), stream(stream) {}
|
||||||
};
|
};
|
||||||
|
|
||||||
BOOL CALLBACK straceWin::EnumModulesCB(LPCSTR ModuleName, DWORD64 BaseOfDll, PVOID UserContext) {
|
BOOL CALLBACK straceWin::EnumModulesCB(LPCSTR ModuleName, DWORD64 BaseOfDll, PVOID UserContext)
|
||||||
|
{
|
||||||
|
Q_UNUSED(ModuleName)
|
||||||
IMAGEHLP_MODULE64 mod;
|
IMAGEHLP_MODULE64 mod;
|
||||||
EnumModulesContext *context = (EnumModulesContext *)UserContext;
|
EnumModulesContext* context = (EnumModulesContext*)UserContext;
|
||||||
mod.SizeOfStruct = sizeof(IMAGEHLP_MODULE64);
|
mod.SizeOfStruct = sizeof(IMAGEHLP_MODULE64);
|
||||||
if(SymGetModuleInfo64(context->hProcess, BaseOfDll, &mod)) {
|
if(SymGetModuleInfo64(context->hProcess, BaseOfDll, &mod)) {
|
||||||
QString moduleBase = QString("0x%1").arg(BaseOfDll, 8, 16, QLatin1Char('0'));
|
QString moduleBase = QString("0x%1").arg(BaseOfDll, 16, 16, QLatin1Char('0'));
|
||||||
QString line = QString("%1 %2 Image: %3")
|
QString line = QString("%1 %2 Image: %3")
|
||||||
.arg(mod.ModuleName, -14)
|
.arg(mod.ModuleName, -25)
|
||||||
.arg(moduleBase, -13)
|
.arg(moduleBase, -13)
|
||||||
.arg(mod.LoadedImageName);
|
.arg(mod.LoadedImageName);
|
||||||
context->stream << line << '\n';
|
context->stream << line << '\n';
|
||||||
|
@ -79,14 +107,15 @@ BOOL CALLBACK straceWin::EnumModulesCB(LPCSTR ModuleName, DWORD64 BaseOfDll, PVO
|
||||||
|
|
||||||
|
|
||||||
#if defined( _M_IX86 ) && defined(Q_CC_MSVC)
|
#if defined( _M_IX86 ) && defined(Q_CC_MSVC)
|
||||||
// Disable global optimization and ignore /GS waning caused by
|
// Disable global optimization and ignore /GS waning caused by
|
||||||
// inline assembly.
|
// inline assembly.
|
||||||
// not needed with mingw cause we can tell mingw which registers we use
|
// not needed with mingw cause we can tell mingw which registers we use
|
||||||
#pragma optimize("g", off)
|
#pragma optimize("g", off)
|
||||||
#pragma warning(push)
|
#pragma warning(push)
|
||||||
#pragma warning(disable : 4748)
|
#pragma warning(disable : 4748)
|
||||||
#endif
|
#endif
|
||||||
const QString straceWin::getBacktrace() {
|
const QString straceWin::getBacktrace()
|
||||||
|
{
|
||||||
DWORD MachineType;
|
DWORD MachineType;
|
||||||
CONTEXT Context;
|
CONTEXT Context;
|
||||||
STACKFRAME64 StackFrame;
|
STACKFRAME64 StackFrame;
|
||||||
|
@ -97,14 +126,14 @@ const QString straceWin::getBacktrace() {
|
||||||
|
|
||||||
|
|
||||||
#ifdef __MINGW32__
|
#ifdef __MINGW32__
|
||||||
asm("Label:\n\t"
|
asm ("Label:\n\t"
|
||||||
"movl %%ebp,%0;\n\t"
|
"movl %%ebp,%0;\n\t"
|
||||||
"movl %%esp,%1;\n\t"
|
"movl %%esp,%1;\n\t"
|
||||||
"movl $Label,%%eax;\n\t"
|
"movl $Label,%%eax;\n\t"
|
||||||
"movl %%eax,%2;\n\t"
|
"movl %%eax,%2;\n\t"
|
||||||
:"=r"(Context.Ebp),"=r"(Context.Esp),"=r"(Context.Eip)
|
: "=r" (Context.Ebp),"=r" (Context.Esp),"=r" (Context.Eip)
|
||||||
://no input
|
: //no input
|
||||||
:"eax");
|
: "eax");
|
||||||
#else
|
#else
|
||||||
_asm {
|
_asm {
|
||||||
Label:
|
Label:
|
||||||
|
@ -141,12 +170,12 @@ const QString straceWin::getBacktrace() {
|
||||||
StackFrame.AddrPC.Mode = AddrModeFlat;
|
StackFrame.AddrPC.Mode = AddrModeFlat;
|
||||||
StackFrame.AddrFrame.Offset = Context.IntSp;
|
StackFrame.AddrFrame.Offset = Context.IntSp;
|
||||||
StackFrame.AddrFrame.Mode = AddrModeFlat;
|
StackFrame.AddrFrame.Mode = AddrModeFlat;
|
||||||
StackFrame.AddrBStore.Offset= Context.RsBSP;
|
StackFrame.AddrBStore.Offset = Context.RsBSP;
|
||||||
StackFrame.AddrBStore.Mode = AddrModeFlat;
|
StackFrame.AddrBStore.Mode = AddrModeFlat;
|
||||||
StackFrame.AddrStack.Offset = Context.IntSp;
|
StackFrame.AddrStack.Offset = Context.IntSp;
|
||||||
StackFrame.AddrStack.Mode = AddrModeFlat;
|
StackFrame.AddrStack.Mode = AddrModeFlat;
|
||||||
#else
|
#else
|
||||||
#error "Unsupported platform"
|
#error "Unsupported platform"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
QString log;
|
QString log;
|
||||||
|
@ -160,7 +189,7 @@ const QString straceWin::getBacktrace() {
|
||||||
DWORD64 dwDisplacement;
|
DWORD64 dwDisplacement;
|
||||||
|
|
||||||
ULONG64 buffer[(sizeof(SYMBOL_INFO) +
|
ULONG64 buffer[(sizeof(SYMBOL_INFO) +
|
||||||
MAX_SYM_NAME*sizeof(TCHAR) +
|
MAX_SYM_NAME * sizeof(TCHAR) +
|
||||||
sizeof(ULONG64) - 1) / sizeof(ULONG64)];
|
sizeof(ULONG64) - 1) / sizeof(ULONG64)];
|
||||||
PSYMBOL_INFO pSymbol = (PSYMBOL_INFO)buffer;
|
PSYMBOL_INFO pSymbol = (PSYMBOL_INFO)buffer;
|
||||||
pSymbol->SizeOfStruct = sizeof(SYMBOL_INFO);
|
pSymbol->SizeOfStruct = sizeof(SYMBOL_INFO);
|
||||||
|
@ -173,6 +202,7 @@ const QString straceWin::getBacktrace() {
|
||||||
ZeroMemory(&ihsf, sizeof(IMAGEHLP_STACK_FRAME));
|
ZeroMemory(&ihsf, sizeof(IMAGEHLP_STACK_FRAME));
|
||||||
|
|
||||||
int i = 0;
|
int i = 0;
|
||||||
|
|
||||||
while(StackWalk64(MachineType, hProcess, hThread, &StackFrame, &Context, NULL, NULL, NULL, NULL)) {
|
while(StackWalk64(MachineType, hProcess, hThread, &StackFrame, &Context, NULL, NULL, NULL, NULL)) {
|
||||||
if(i == 128)
|
if(i == 128)
|
||||||
break;
|
break;
|
||||||
|
@ -190,23 +220,38 @@ const QString straceWin::getBacktrace() {
|
||||||
QString funcName;
|
QString funcName;
|
||||||
if(SymFromAddr(hProcess, ihsf.InstructionOffset, &dwDisplacement, pSymbol)) {
|
if(SymFromAddr(hProcess, ihsf.InstructionOffset, &dwDisplacement, pSymbol)) {
|
||||||
funcName = QString(pSymbol->Name);
|
funcName = QString(pSymbol->Name);
|
||||||
} else {
|
#ifdef __MINGW32__
|
||||||
|
demangle(funcName);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
else {
|
||||||
funcName = QString("0x%1").arg(ihsf.InstructionOffset, 8, 16, QLatin1Char('0'));
|
funcName = QString("0x%1").arg(ihsf.InstructionOffset, 8, 16, QLatin1Char('0'));
|
||||||
}
|
}
|
||||||
QStringList params;
|
|
||||||
SymSetContext(hProcess, &ihsf, NULL);
|
SymSetContext(hProcess, &ihsf, NULL);
|
||||||
|
#ifndef __MINGW32__
|
||||||
|
QStringList params;
|
||||||
SymEnumSymbols(hProcess, 0, NULL, EnumSymbolsCB, (PVOID)¶ms);
|
SymEnumSymbols(hProcess, 0, NULL, EnumSymbolsCB, (PVOID)¶ms);
|
||||||
|
#endif
|
||||||
|
|
||||||
QString insOffset = QString("0x%1").arg(ihsf.InstructionOffset, 8, 16, QLatin1Char('0'));
|
QString insOffset = QString("0x%1").arg(ihsf.InstructionOffset, 16, 16, QLatin1Char('0'));
|
||||||
QString debugLine = QString("#%1 %2 %3 %4(%5)")
|
QString formatLine = "#%1 %2 %3 %4";
|
||||||
|
#ifndef __MINGW32__
|
||||||
|
formatLine += "(%5)";
|
||||||
|
#endif
|
||||||
|
QString debugLine = formatLine
|
||||||
.arg(i, 3, 10)
|
.arg(i, 3, 10)
|
||||||
.arg(fileName, -20)
|
.arg(fileName, -20)
|
||||||
.arg(insOffset, -11)
|
.arg(insOffset, -11)
|
||||||
.arg(funcName)
|
.arg(funcName)
|
||||||
|
#ifndef __MINGW32__
|
||||||
.arg(params.join(", "));
|
.arg(params.join(", "));
|
||||||
|
#else
|
||||||
|
;
|
||||||
|
#endif
|
||||||
logStream << debugLine << '\n';
|
logStream << debugLine << '\n';
|
||||||
i++;
|
i++;
|
||||||
} else {
|
}
|
||||||
|
else {
|
||||||
break; // we're at the end.
|
break; // we're at the end.
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -218,6 +263,6 @@ const QString straceWin::getBacktrace() {
|
||||||
return log;
|
return log;
|
||||||
}
|
}
|
||||||
#if defined(_M_IX86) && defined(Q_CC_MSVC)
|
#if defined(_M_IX86) && defined(Q_CC_MSVC)
|
||||||
#pragma warning(pop)
|
#pragma warning(pop)
|
||||||
#pragma optimize("g", on)
|
#pragma optimize("g", on)
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -7,17 +7,22 @@
|
||||||
#include "libtorrent/version.hpp"
|
#include "libtorrent/version.hpp"
|
||||||
#include "ui_stacktrace_win_dlg.h"
|
#include "ui_stacktrace_win_dlg.h"
|
||||||
|
|
||||||
class StraceDlg : public QDialog, private Ui::errorDialog {
|
class StraceDlg: public QDialog, private Ui::errorDialog
|
||||||
|
{
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
|
|
||||||
public:
|
public:
|
||||||
StraceDlg(QWidget *parent = 0): QDialog(parent) {
|
StraceDlg(QWidget* parent = 0): QDialog(parent)
|
||||||
|
{
|
||||||
setupUi(this);
|
setupUi(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
~StraceDlg() {}
|
~StraceDlg()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
void setStacktraceString(const QString& trace) {
|
void setStacktraceString(const QString& trace)
|
||||||
|
{
|
||||||
QString htmlStr;
|
QString htmlStr;
|
||||||
QTextStream outStream(&htmlStr);
|
QTextStream outStream(&htmlStr);
|
||||||
outStream << "<p align=center><b><font size=7 color=red>" <<
|
outStream << "<p align=center><b><font size=7 color=red>" <<
|
||||||
|
|
|
@ -4,13 +4,17 @@ strace_win:{
|
||||||
QMAKE_CXXFLAGS_RELEASE += -fno-omit-frame-pointer
|
QMAKE_CXXFLAGS_RELEASE += -fno-omit-frame-pointer
|
||||||
QMAKE_CXXFLAGS_DEBUG += -fno-omit-frame-pointer
|
QMAKE_CXXFLAGS_DEBUG += -fno-omit-frame-pointer
|
||||||
}
|
}
|
||||||
release:{
|
|
||||||
#QMAKE_CXXFLAGS_RELEASE += -g
|
QMAKE_LFLAGS += -Wl,--export-all-symbols
|
||||||
#QMAKE_LFLAGS_RELEASE -= -Wl,-s
|
|
||||||
}
|
|
||||||
LIBS += libdbghelp
|
LIBS += libdbghelp
|
||||||
}
|
}
|
||||||
|
|
||||||
|
CONFIG(debug, debug|release) {
|
||||||
|
# Make sure binary is not relocatable, otherwise debugging will fail
|
||||||
|
QMAKE_LFLAGS -= -Wl,--dynamicbase
|
||||||
|
}
|
||||||
|
|
||||||
RC_FILE = qbittorrent_mingw.rc
|
RC_FILE = qbittorrent_mingw.rc
|
||||||
|
|
||||||
#You need to link with libtorrent > 0.15.5 (or svn) and you must
|
#You need to link with libtorrent > 0.15.5 (or svn) and you must
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue