Nick Tiskov
12 years ago
5 changed files with 356 additions and 2 deletions
@ -0,0 +1,221 @@
@@ -0,0 +1,221 @@
|
||||
/***************************************************************************
|
||||
* 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. * |
||||
***************************************************************************/ |
||||
|
||||
#include <windows.h> |
||||
#include <dbghelp.h> |
||||
#include <stdio.h> |
||||
|
||||
#include <QTextStream> |
||||
|
||||
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; |
||||
} |
||||
|
||||
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) { |
||||
QStringList *params = (QStringList *)user; |
||||
if(symInfo->Flags & SYMFLAG_PARAMETER) { |
||||
params->append(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) { |
||||
IMAGEHLP_MODULE64 mod; |
||||
EnumModulesContext *context = (EnumModulesContext *)UserContext; |
||||
mod.SizeOfStruct = sizeof(IMAGEHLP_MODULE64); |
||||
if(SymGetModuleInfo64(context->hProcess, BaseOfDll, &mod)) { |
||||
QString moduleBase = QString("0x%1").arg(BaseOfDll, 8, 16, QLatin1Char('0')); |
||||
QString line = QString("%1 %2 Image: %3") |
||||
.arg(mod.ModuleName, -14) |
||||
.arg(moduleBase, -13) |
||||
.arg(mod.LoadedImageName); |
||||
context->stream << line << '\n'; |
||||
|
||||
QString pdbName(mod.LoadedPdbName); |
||||
if(!pdbName.isEmpty()) { |
||||
QString line2 = QString("%1 %2") |
||||
.arg("", 35) |
||||
.arg(pdbName); |
||||
context->stream << line2 << '\n'; |
||||
} |
||||
} |
||||
return TRUE; |
||||
} |
||||
|
||||
|
||||
|
||||
#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); |
||||
|
||||
HANDLE hProcess = GetCurrentProcess(); |
||||
HANDLE hThread = GetCurrentThread(); |
||||
SymInitialize(hProcess, NULL, TRUE); |
||||
|
||||
DWORD64 dwDisplacement; |
||||
|
||||
ULONG64 buffer[(sizeof(SYMBOL_INFO) + |
||||
MAX_SYM_NAME*sizeof(TCHAR) + |
||||
sizeof(ULONG64) - 1) / sizeof(ULONG64)]; |
||||
PSYMBOL_INFO pSymbol = (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.
|
||||
|
||||
QString fileName("???"); |
||||
if(SymGetModuleInfo64(hProcess, ihsf.InstructionOffset, &mod)) { |
||||
fileName = QString(mod.ImageName); |
||||
int slashPos = fileName.lastIndexOf('\\'); |
||||
if(slashPos != -1) |
||||
fileName = fileName.mid(slashPos + 1); |
||||
} |
||||
QString funcName; |
||||
if(SymFromAddr(hProcess, ihsf.InstructionOffset, &dwDisplacement, pSymbol)) { |
||||
funcName = QString(pSymbol->Name); |
||||
} else { |
||||
funcName = QString("0x%1").arg(ihsf.InstructionOffset, 8, 16, QLatin1Char('0')); |
||||
} |
||||
QStringList params; |
||||
SymSetContext(hProcess, &ihsf, NULL); |
||||
SymEnumSymbols(hProcess, 0, NULL, EnumSymbolsCB, (PVOID)¶ms); |
||||
|
||||
QString insOffset = QString("0x%1").arg(ihsf.InstructionOffset, 8, 16, QLatin1Char('0')); |
||||
QString debugLine = QString("#%1 %2 %3 %4(%5)") |
||||
.arg(i, 3, 10) |
||||
.arg(fileName, -20) |
||||
.arg(insOffset, -11) |
||||
.arg(funcName) |
||||
.arg(params.join(", ")); |
||||
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); |
||||
return log; |
||||
} |
||||
#if defined(_M_IX86) && defined(Q_CC_MSVC) |
||||
#pragma warning(pop) |
||||
#pragma optimize("g", on) |
||||
#endif |
@ -0,0 +1,49 @@
@@ -0,0 +1,49 @@
|
||||
#ifndef STACKTRACE_WIN_DLG_H |
||||
#define STACKTRACE_WIN_DLG_H |
||||
|
||||
#include <QTextStream> |
||||
#include <QClipboard> |
||||
#include "boost/version.hpp" |
||||
#include "libtorrent/version.hpp" |
||||
#include "ui_stacktrace_win_dlg.h" |
||||
|
||||
class StraceDlg : public QDialog, private Ui::errorDialog { |
||||
Q_OBJECT |
||||
|
||||
public: |
||||
StraceDlg(QWidget *parent = 0): QDialog(parent) { |
||||
setupUi(this); |
||||
} |
||||
|
||||
~StraceDlg() {} |
||||
|
||||
void setStacktraceString(const QString& trace) { |
||||
QString htmlStr; |
||||
QTextStream outStream(&htmlStr); |
||||
outStream << "<p align=center><b><font size=7 color=red>" << |
||||
"qBittorrent has crashed" << |
||||
"</font></b></p>" << |
||||
"<font size=4>" << |
||||
"<p>" << |
||||
"Please report a bug at <a href=\"http://bugs.qbittorrent.org\">" << |
||||
"http://bugs.qbittorrent.org</a>" << |
||||
" and provide the following backtrace." << |
||||
"</p>" << |
||||
"</font>" << |
||||
"<br/><hr><br/>" << |
||||
"<p align=center><font size=4>qBittorrent version: " << VERSION << |
||||
"<br/>Libtorrent version: " << LIBTORRENT_VERSION << |
||||
"<br/>Qt version: " << QT_VERSION_STR << |
||||
"<br/>Boost version: " << QString::number(BOOST_VERSION / 100000) << '.' << |
||||
QString::number((BOOST_VERSION / 100) % 1000) << '.' << |
||||
QString::number(BOOST_VERSION % 100) << "</font></p><br/>" |
||||
"<pre><code>" << |
||||
trace << |
||||
"</code></pre>" << |
||||
"<br/><hr><br/><br/>"; |
||||
|
||||
errorText->setHtml(htmlStr); |
||||
} |
||||
}; |
||||
|
||||
#endif |
@ -0,0 +1,35 @@
@@ -0,0 +1,35 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?> |
||||
<ui version="4.0"> |
||||
<class>errorDialog</class> |
||||
<widget class="QDialog" name="errorDialog"> |
||||
<property name="geometry"> |
||||
<rect> |
||||
<x>0</x> |
||||
<y>0</y> |
||||
<width>640</width> |
||||
<height>480</height> |
||||
</rect> |
||||
</property> |
||||
<property name="windowTitle"> |
||||
<string>Crash info</string> |
||||
</property> |
||||
<layout class="QVBoxLayout" name="verticalLayout"> |
||||
<item> |
||||
<widget class="QTextBrowser" name="errorText"> |
||||
<property name="html"> |
||||
<string notr="true"><!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> |
||||
<html><head><meta name="qrichtext" content="1" /><style type="text/css"> |
||||
p, li { white-space: pre-wrap; } |
||||
</style></head><body style=" font-family:'MS Shell Dlg 2'; font-size:8.25pt; font-weight:400; font-style:normal;"> |
||||
<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-size:8pt;"><br /></p></body></html></string> |
||||
</property> |
||||
<property name="openExternalLinks"> |
||||
<bool>true</bool> |
||||
</property> |
||||
</widget> |
||||
</item> |
||||
</layout> |
||||
</widget> |
||||
<resources/> |
||||
<connections/> |
||||
</ui> |
Loading…
Reference in new issue