1 /***************************************************************************
\r
2 * Copyright (C) 2005-08 by the Quassel IRC Team *
\r
3 * devel@quassel-irc.org *
\r
5 * This program is free software; you can redistribute it and/or modify *
\r
6 * it under the terms of the GNU General Public License as published by *
\r
7 * the Free Software Foundation; either version 2 of the License, or *
\r
8 * (at your option) version 3. *
\r
10 * This program is distributed in the hope that it will be useful, *
\r
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of *
\r
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
\r
13 * GNU General Public License for more details. *
\r
15 * You should have received a copy of the GNU General Public License *
\r
16 * along with this program; if not, write to the *
\r
17 * Free Software Foundation, Inc., *
\r
18 * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
\r
19 ***************************************************************************/
\r
21 #include "quassel.h"
\r
23 #include <windows.h>
\r
24 #include <dbghelp.h>
\r
27 // #include <QDebug>
\r
29 #include <QTextStream>
\r
31 void loadHelpStackFrame(IMAGEHLP_STACK_FRAME &ihsf, const STACKFRAME64 &stackFrame) {
\r
32 ZeroMemory(&ihsf, sizeof(IMAGEHLP_STACK_FRAME));
\r
33 ihsf.InstructionOffset = stackFrame.AddrPC.Offset;
\r
34 ihsf.FrameOffset = stackFrame.AddrFrame.Offset;
\r
37 BOOL CALLBACK EnumSymbolsCB(PSYMBOL_INFO symInfo, ULONG size, PVOID user) {
\r
38 QStringList *params = (QStringList *)user;
\r
39 if(symInfo->Flags & SYMFLAG_PARAMETER) {
\r
40 params->append(symInfo->Name);
\r
46 struct EnumModulesContext {
\r
48 QTextStream &stream;
\r
49 EnumModulesContext(HANDLE hProcess, QTextStream &stream) : hProcess(hProcess), stream(stream) {}
\r
52 BOOL CALLBACK EnumModulesCB(PCTSTR ModuleName, DWORD64 BaseOfDll, PVOID UserContext) {
\r
53 IMAGEHLP_MODULE64 mod;
\r
54 EnumModulesContext *context = (EnumModulesContext *)UserContext;
\r
55 mod.SizeOfStruct = sizeof(IMAGEHLP_MODULE64);
\r
56 if(SymGetModuleInfo64(context->hProcess, BaseOfDll, &mod)) {
\r
57 QString line = QString("%1 0x%2 Image: %3").arg(mod.ModuleName, -14)
\r
58 .arg(BaseOfDll, 8, 16, QLatin1Char('0'))
\r
59 .arg(mod.LoadedImageName);
\r
60 // qDebug() << qPrintable(line);
\r
61 context->stream << line << '\n';
\r
63 QString pdbName(mod.LoadedPdbName);
\r
64 if(!pdbName.isEmpty()) {
\r
65 QString line2 = QString("%1 %2").arg("", 32).arg(pdbName);
\r
66 // qDebug() << qPrintable(line2);
\r
67 context->stream << line2 << '\n';
\r
74 // Disable global optimization and ignore /GS waning caused by
\r
76 #pragma optimize("g", off)
\r
77 #pragma warning(push)
\r
78 #pragma warning(disable : 4748)
\r
80 void Quassel::logBacktrace(const QString &filename) {
\r
83 STACKFRAME64 StackFrame;
\r
86 ZeroMemory(&Context, sizeof(CONTEXT));
\r
87 Context.ContextFlags = CONTEXT_CONTROL;
\r
90 mov [Context.Ebp], ebp;
\r
91 mov [Context.Esp], esp;
\r
93 mov [Context.Eip], eax;
\r
96 RtlCaptureContext(&Context);
\r
99 ZeroMemory(&StackFrame, sizeof(STACKFRAME64));
\r
101 MachineType = IMAGE_FILE_MACHINE_I386;
\r
102 StackFrame.AddrPC.Offset = Context.Eip;
\r
103 StackFrame.AddrPC.Mode = AddrModeFlat;
\r
104 StackFrame.AddrFrame.Offset = Context.Ebp;
\r
105 StackFrame.AddrFrame.Mode = AddrModeFlat;
\r
106 StackFrame.AddrStack.Offset = Context.Esp;
\r
107 StackFrame.AddrStack.Mode = AddrModeFlat;
\r
109 MachineType = IMAGE_FILE_MACHINE_AMD64;
\r
110 StackFrame.AddrPC.Offset = Context.Rip;
\r
111 StackFrame.AddrPC.Mode = AddrModeFlat;
\r
112 StackFrame.AddrFrame.Offset = Context.Rsp;
\r
113 StackFrame.AddrFrame.Mode = AddrModeFlat;
\r
114 StackFrame.AddrStack.Offset = Context.Rsp;
\r
115 StackFrame.AddrStack.Mode = AddrModeFlat;
\r
117 MachineType = IMAGE_FILE_MACHINE_IA64;
\r
118 StackFrame.AddrPC.Offset = Context.StIIP;
\r
119 StackFrame.AddrPC.Mode = AddrModeFlat;
\r
120 StackFrame.AddrFrame.Offset = Context.IntSp;
\r
121 StackFrame.AddrFrame.Mode = AddrModeFlat;
\r
122 StackFrame.AddrBStore.Offset= Context.RsBSP;
\r
123 StackFrame.AddrBStore.Mode = AddrModeFlat;
\r
124 StackFrame.AddrStack.Offset = Context.IntSp;
\r
125 StackFrame.AddrStack.Mode = AddrModeFlat;
\r
127 #error "Unsupported platform"
\r
130 //EnterCriticalSection(&DbgHelpLock);
\r
132 QFile logFile(filename);
\r
133 logFile.open(QIODevice::Append);
\r
134 QTextStream logStream(&logFile);
\r
136 HANDLE hProcess = GetCurrentProcess();
\r
137 HANDLE hThread = GetCurrentThread();
\r
138 SymInitialize(hProcess, NULL, TRUE);
\r
140 DWORD64 dwDisplacement;
\r
142 ULONG64 buffer[(sizeof(SYMBOL_INFO) +
\r
143 MAX_SYM_NAME*sizeof(TCHAR) +
\r
144 sizeof(ULONG64) - 1) / sizeof(ULONG64)];
\r
145 PSYMBOL_INFO pSymbol = (PSYMBOL_INFO)buffer;
\r
146 pSymbol->SizeOfStruct = sizeof(SYMBOL_INFO);
\r
147 pSymbol->MaxNameLen = MAX_SYM_NAME;
\r
149 IMAGEHLP_MODULE64 mod;
\r
150 mod.SizeOfStruct = sizeof(IMAGEHLP_MODULE64);
\r
152 IMAGEHLP_STACK_FRAME ihsf;
\r
153 ZeroMemory(&ihsf, sizeof(IMAGEHLP_STACK_FRAME));
\r
156 while(StackWalk64(MachineType, hProcess, hThread, &StackFrame, &Context, NULL, NULL, NULL, NULL)) {
\r
160 loadHelpStackFrame(ihsf, StackFrame);
\r
161 if(StackFrame.AddrPC.Offset != 0) { // Valid frame.
\r
163 QString fileName("???");
\r
164 if(SymGetModuleInfo64(hProcess, ihsf.InstructionOffset, &mod)) {
\r
165 fileName = QString(mod.ImageName);
\r
166 int slashPos = fileName.lastIndexOf('\\');
\r
168 fileName = fileName.mid(slashPos + 1);
\r
171 if(SymFromAddr(hProcess, ihsf.InstructionOffset, &dwDisplacement, pSymbol)) {
\r
172 funcName = QString(pSymbol->Name);
\r
174 funcName = QString("0x%1").arg(ihsf.InstructionOffset, 8, 16, QLatin1Char('0'));
\r
176 QStringList params;
\r
177 SymSetContext(hProcess, &ihsf, NULL);
\r
178 SymEnumSymbols(hProcess, 0, NULL, EnumSymbolsCB, (PVOID)¶ms);
\r
180 QString debugLine = QString("#%1 %2 0x%3 %4(%5)").arg(i, 3, 10)
\r
181 .arg(fileName, -20)
\r
182 .arg(ihsf.InstructionOffset, 8, 16, QLatin1Char('0'))
\r
184 .arg(params.join(", "));
\r
185 // qDebug() << qPrintable(debugLine);
\r
186 logStream << debugLine << '\n';
\r
189 break; // we're at the end.
\r
193 // qDebug() << "List of linked Modules:";
\r
194 logStream << "\n\nList of linked Modules:\n";
\r
195 EnumModulesContext modulesContext(hProcess, logStream);
\r
196 SymEnumerateModules64(hProcess, EnumModulesCB, (PVOID)&modulesContext);
\r
201 #pragma warning(pop)
\r
202 #pragma optimize("g", on)
\r