+/***************************************************************************\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