-/***************************************************************************\r
- * Copyright (C) 2005-08 by the Quassel IRC Team *\r
- * devel@quassel-irc.org *\r
- * *\r
- * This program is free software; you can redistribute it and/or modify *\r
- * it under the terms of the GNU General Public License as published by *\r
- * the Free Software Foundation; either version 2 of the License, or *\r
- * (at your option) version 3. *\r
- * *\r
- * This program is distributed in the hope that it will be useful, *\r
- * but WITHOUT ANY WARRANTY; without even the implied warranty of *\r
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *\r
- * GNU General Public License for more details. *\r
- * *\r
- * You should have received a copy of the GNU General Public License *\r
- * along with this program; if not, write to the *\r
- * Free Software Foundation, Inc., *\r
- * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *\r
- ***************************************************************************/\r
-\r
-#include "quassel.h"\r
-\r
-#include <windows.h>\r
-#include <dbghelp.h>\r
-#include <stdio.h>\r
-\r
-// #include <QDebug>\r
-#include <QFile>\r
-#include <QTextStream>\r
-\r
-void loadHelpStackFrame(IMAGEHLP_STACK_FRAME &ihsf, const STACKFRAME64 &stackFrame) {\r
- ZeroMemory(&ihsf, sizeof(IMAGEHLP_STACK_FRAME));\r
- ihsf.InstructionOffset = stackFrame.AddrPC.Offset;\r
- ihsf.FrameOffset = stackFrame.AddrFrame.Offset;\r
-}\r
-\r
-BOOL CALLBACK EnumSymbolsCB(PSYMBOL_INFO symInfo, ULONG size, PVOID user) { \r
- QStringList *params = (QStringList *)user;\r
- if(symInfo->Flags & SYMFLAG_PARAMETER) {\r
- params->append(symInfo->Name);\r
- }\r
- return TRUE;\r
-}\r
-\r
-\r
-struct EnumModulesContext {\r
- HANDLE hProcess;\r
- QTextStream &stream;\r
- EnumModulesContext(HANDLE hProcess, QTextStream &stream) : hProcess(hProcess), stream(stream) {}\r
-};\r
-\r
-BOOL CALLBACK EnumModulesCB(PCTSTR ModuleName, DWORD64 BaseOfDll, PVOID UserContext) {\r
- IMAGEHLP_MODULE64 mod;\r
- EnumModulesContext *context = (EnumModulesContext *)UserContext;\r
- mod.SizeOfStruct = sizeof(IMAGEHLP_MODULE64);\r
- if(SymGetModuleInfo64(context->hProcess, BaseOfDll, &mod)) {\r
- QString line = QString("%1 0x%2 Image: %3").arg(mod.ModuleName, -14)\r
- .arg(BaseOfDll, 8, 16, QLatin1Char('0'))\r
- .arg(mod.LoadedImageName);\r
- // qDebug() << qPrintable(line);\r
- context->stream << line << '\n';\r
- \r
- QString pdbName(mod.LoadedPdbName);\r
- if(!pdbName.isEmpty()) {\r
- QString line2 = QString("%1 %2").arg("", 32).arg(pdbName);\r
- // qDebug() << qPrintable(line2);\r
- context->stream << line2 << '\n';\r
- }\r
- }\r
- return TRUE;\r
-}\r
-\r
-#ifdef _M_IX86\r
- // Disable global optimization and ignore /GS waning caused by\r
- // inline assembly.\r
- #pragma optimize("g", off)\r
- #pragma warning(push)\r
- #pragma warning(disable : 4748)\r
-#endif\r
-void Quassel::logBacktrace(const QString &filename) {\r
- DWORD MachineType;\r
- CONTEXT Context;\r
- STACKFRAME64 StackFrame;\r
-\r
-#ifdef _M_IX86\r
- ZeroMemory(&Context, sizeof(CONTEXT));\r
- Context.ContextFlags = CONTEXT_CONTROL;\r
- __asm {\r
- Label:\r
- mov [Context.Ebp], ebp;\r
- mov [Context.Esp], esp;\r
- mov eax, [Label];\r
- mov [Context.Eip], eax;\r
- }\r
-#else\r
- RtlCaptureContext(&Context);\r
-#endif\r
-\r
- ZeroMemory(&StackFrame, sizeof(STACKFRAME64));\r
-#ifdef _M_IX86\r
- MachineType = IMAGE_FILE_MACHINE_I386;\r
- StackFrame.AddrPC.Offset = Context.Eip;\r
- StackFrame.AddrPC.Mode = AddrModeFlat;\r
- StackFrame.AddrFrame.Offset = Context.Ebp;\r
- StackFrame.AddrFrame.Mode = AddrModeFlat;\r
- StackFrame.AddrStack.Offset = Context.Esp;\r
- StackFrame.AddrStack.Mode = AddrModeFlat;\r
-#elif _M_X64\r
- MachineType = IMAGE_FILE_MACHINE_AMD64;\r
- StackFrame.AddrPC.Offset = Context.Rip;\r
- StackFrame.AddrPC.Mode = AddrModeFlat;\r
- StackFrame.AddrFrame.Offset = Context.Rsp;\r
- StackFrame.AddrFrame.Mode = AddrModeFlat;\r
- StackFrame.AddrStack.Offset = Context.Rsp;\r
- StackFrame.AddrStack.Mode = AddrModeFlat;\r
-#elif _M_IA64\r
- MachineType = IMAGE_FILE_MACHINE_IA64;\r
- StackFrame.AddrPC.Offset = Context.StIIP;\r
- StackFrame.AddrPC.Mode = AddrModeFlat;\r
- StackFrame.AddrFrame.Offset = Context.IntSp;\r
- StackFrame.AddrFrame.Mode = AddrModeFlat;\r
- StackFrame.AddrBStore.Offset= Context.RsBSP;\r
- StackFrame.AddrBStore.Mode = AddrModeFlat;\r
- StackFrame.AddrStack.Offset = Context.IntSp;\r
- StackFrame.AddrStack.Mode = AddrModeFlat;\r
-#else\r
- #error "Unsupported platform"\r
-#endif\r
-\r
- //EnterCriticalSection(&DbgHelpLock);\r
-\r
- QFile logFile(filename);\r
- logFile.open(QIODevice::Append);\r
- QTextStream logStream(&logFile);\r
-\r
- HANDLE hProcess = GetCurrentProcess();\r
- HANDLE hThread = GetCurrentThread();\r
- SymInitialize(hProcess, NULL, TRUE);\r
-\r
- DWORD64 dwDisplacement;\r
-\r
- ULONG64 buffer[(sizeof(SYMBOL_INFO) +\r
- MAX_SYM_NAME*sizeof(TCHAR) +\r
- sizeof(ULONG64) - 1) / sizeof(ULONG64)];\r
- PSYMBOL_INFO pSymbol = (PSYMBOL_INFO)buffer;\r
- pSymbol->SizeOfStruct = sizeof(SYMBOL_INFO);\r
- pSymbol->MaxNameLen = MAX_SYM_NAME;\r
- \r
- IMAGEHLP_MODULE64 mod;\r
- mod.SizeOfStruct = sizeof(IMAGEHLP_MODULE64);\r
-\r
- IMAGEHLP_STACK_FRAME ihsf;\r
- ZeroMemory(&ihsf, sizeof(IMAGEHLP_STACK_FRAME));\r
-\r
- int i = 0;\r
- while(StackWalk64(MachineType, hProcess, hThread, &StackFrame, &Context, NULL, NULL, NULL, NULL)) {\r
- if(i == 128)\r
- break;\r
-\r
- loadHelpStackFrame(ihsf, StackFrame);\r
- if(StackFrame.AddrPC.Offset != 0) { // Valid frame.\r
- \r
- QString fileName("???");\r
- if(SymGetModuleInfo64(hProcess, ihsf.InstructionOffset, &mod)) {\r
- fileName = QString(mod.ImageName);\r
- int slashPos = fileName.lastIndexOf('\\');\r
- if(slashPos != -1)\r
- fileName = fileName.mid(slashPos + 1);\r
- }\r
- QString funcName;\r
- if(SymFromAddr(hProcess, ihsf.InstructionOffset, &dwDisplacement, pSymbol)) {\r
- funcName = QString(pSymbol->Name);\r
- } else {\r
- funcName = QString("0x%1").arg(ihsf.InstructionOffset, 8, 16, QLatin1Char('0'));\r
- }\r
- QStringList params;\r
- SymSetContext(hProcess, &ihsf, NULL);\r
- SymEnumSymbols(hProcess, 0, NULL, EnumSymbolsCB, (PVOID)¶ms);\r
- \r
- QString debugLine = QString("#%1 %2 0x%3 %4(%5)").arg(i, 3, 10)\r
- .arg(fileName, -20)\r
- .arg(ihsf.InstructionOffset, 8, 16, QLatin1Char('0'))\r
- .arg(funcName)\r
- .arg(params.join(", "));\r
- // qDebug() << qPrintable(debugLine);\r
- logStream << debugLine << '\n';\r
- i++;\r
- } else {\r
- break; // we're at the end.\r
- }\r
- }\r
-\r
- // qDebug() << "List of linked Modules:";\r
- logStream << "\n\nList of linked Modules:\n";\r
- EnumModulesContext modulesContext(hProcess, logStream);\r
- SymEnumerateModules64(hProcess, EnumModulesCB, (PVOID)&modulesContext);\r
-\r
- logFile.close();\r
-}\r
-#ifdef _M_IX86\r
- #pragma warning(pop)\r
- #pragma optimize("g", on)\r
-#endif\r
+/***************************************************************************
+ * 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