rendered paste body/***************************************************************************
* 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 "quassel.h"
#include <windows.h>
#include <dbghelp.h>
#include <stdio.h>
// #include <QDebug>
#include <QFile>
#include <QTextStream>
void 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 EnumSymbolsCB(PSYMBOL_INFO symInfo, ULONG size, PVOID user) {
QStringList *params = (QStringList *)user;
if(symInfo->Flags & SYMFLAG_PARAMETER) {
params->append(symInfo->Name);
}
return TRUE;
}
struct EnumModulesContext {
HANDLE hProcess;
QTextStream &stream;
EnumModulesContext(HANDLE hProcess, QTextStream &stream) : hProcess(hProcess), stream(stream) {}
};
BOOL CALLBACK EnumModulesCB(PCTSTR ModuleName, DWORD64 BaseOfDll, PVOID UserContext) {
IMAGEHLP_MODULE64 mod;
EnumModulesContext *context = (EnumModulesContext *)UserContext;
mod.SizeOfStruct = sizeof(IMAGEHLP_MODULE64);
if(SymGetModuleInfo64(context->hProcess, BaseOfDll, &mod)) {
QString line = QString("%1 0x%2 Image: %3").arg(mod.ModuleName, -14)
.arg(BaseOfDll, 8, 16, QLatin1Char('0'))
.arg(mod.LoadedImageName);
// qDebug() << qPrintable(line);
context->stream << line << '\n';
QString pdbName(mod.LoadedPdbName);
if(!pdbName.isEmpty()) {
QString line2 = QString("%1 %2").arg("", 32).arg(pdbName);
// qDebug() << qPrintable(line2);
context->stream << line2 << '\n';
}
}
return TRUE;
}
// we don't use the ModuleName anyways so we can easily "convert" this
inline BOOL CALLBACK EnumModulesCB(PSTR ModuleName, DWORD64 BaseOfDll, PVOID UserContext) {
return EnumModulesCB(PCTSTR(0), BaseOfDll, UserContext);
}
#ifdef _M_IX86
// Disable global optimization and ignore /GS waning caused by
// inline assembly.
#pragma optimize("g", off)
#pragma warning(push)
#pragma warning(disable : 4748)
#endif
void Quassel::logBacktrace(const QString &filename) {
DWORD MachineType;
CONTEXT Context;
STACKFRAME64 StackFrame;
#ifdef _M_IX86
ZeroMemory(&Context, sizeof(CONTEXT));
Context.ContextFlags = CONTEXT_CONTROL;
_asm {
Label:
mov [Context.Ebp], ebp;
mov [Context.Esp], esp;
mov eax, [Label];
mov [Context.Eip], eax;
}
#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
//EnterCriticalSection(&DbgHelpLock);
QFile logFile(filename);
logFile.open(QIODevice::Append);
QTextStream logStream(&logFile);
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 debugLine = QString("#%1 %2 0x%3 %4(%5)").arg(i, 3, 10)
.arg(fileName, -20)
.arg(ihsf.InstructionOffset, 8, 16, QLatin1Char('0'))
.arg(funcName)
.arg(params.join(", "));
// qDebug() << qPrintable(debugLine);
logStream << debugLine << '\n';
i++;
} else {
break; // we're at the end.
}
}
// qDebug() << "List of linked Modules:";
logStream << "\n\nList of linked Modules:\n";
EnumModulesContext modulesContext(hProcess, logStream);
SymEnumerateModules64(hProcess, EnumModulesCB, (PVOID)&modulesContext);
logFile.close();
}
#ifdef _M_IX86
#pragma warning(pop)
#pragma optimize("g", on)
#endif