1 /***************************************************************************
2 * Copyright (C) 2005-09 by the Quassel Project *
3 * devel@quassel-irc.org *
5 * This program is free software; you can redistribute it and/or modify *
6 * it under the terms of the GNU General Public License as published by *
7 * the Free Software Foundation; either version 2 of the License, or *
8 * (at your option) version 3. *
10 * This program is distributed in the hope that it will be useful, *
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of *
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
13 * GNU General Public License for more details. *
15 * You should have received a copy of the GNU General Public License *
16 * along with this program; if not, write to the *
17 * Free Software Foundation, Inc., *
18 * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
19 ***************************************************************************/
29 #include <QTextStream>
31 void loadHelpStackFrame(IMAGEHLP_STACK_FRAME &ihsf, const STACKFRAME64 &stackFrame) {
32 ZeroMemory(&ihsf, sizeof(IMAGEHLP_STACK_FRAME));
33 ihsf.InstructionOffset = stackFrame.AddrPC.Offset;
34 ihsf.FrameOffset = stackFrame.AddrFrame.Offset;
37 BOOL CALLBACK EnumSymbolsCB(PSYMBOL_INFO symInfo, ULONG size, PVOID user) {
38 QStringList *params = (QStringList *)user;
39 if(symInfo->Flags & SYMFLAG_PARAMETER) {
40 params->append(symInfo->Name);
46 struct EnumModulesContext {
49 EnumModulesContext(HANDLE hProcess, QTextStream &stream) : hProcess(hProcess), stream(stream) {}
52 BOOL CALLBACK EnumModulesCB(LPCSTR ModuleName, DWORD64 BaseOfDll, PVOID UserContext) {
53 IMAGEHLP_MODULE64 mod;
54 EnumModulesContext *context = (EnumModulesContext *)UserContext;
55 mod.SizeOfStruct = sizeof(IMAGEHLP_MODULE64);
56 if(SymGetModuleInfo64(context->hProcess, BaseOfDll, &mod)) {
57 QString line = QString("%1 0x%2 Image: %3").arg(mod.ModuleName, -14)
58 .arg(BaseOfDll, 8, 16, QLatin1Char('0'))
59 .arg(mod.LoadedImageName);
60 // qDebug() << qPrintable(line);
61 context->stream << line << '\n';
63 QString pdbName(mod.LoadedPdbName);
64 if(!pdbName.isEmpty()) {
65 QString line2 = QString("%1 %2").arg("", 32).arg(pdbName);
66 // qDebug() << qPrintable(line2);
67 context->stream << line2 << '\n';
75 #if defined( _M_IX86 ) && defined(Q_CC_MSVC)
76 // Disable global optimization and ignore /GS waning caused by
78 // not needed with mingw cause we can tell mingw which registers we use
79 #pragma optimize("g", off)
81 #pragma warning(disable : 4748)
83 void Quassel::logBacktrace(const QString &filename) {
86 STACKFRAME64 StackFrame;
89 ZeroMemory(&Context, sizeof(CONTEXT));
90 Context.ContextFlags = CONTEXT_CONTROL;
97 "movl $Label,%%eax;\n\t"
99 :"=r"(Context.Ebp),"=r"(Context.Esp),"=r"(Context.Eip)
105 mov [Context.Ebp], ebp;
106 mov [Context.Esp], esp;
108 mov [Context.Eip], eax;
112 RtlCaptureContext(&Context);
115 ZeroMemory(&StackFrame, sizeof(STACKFRAME64));
117 MachineType = IMAGE_FILE_MACHINE_I386;
118 StackFrame.AddrPC.Offset = Context.Eip;
119 StackFrame.AddrPC.Mode = AddrModeFlat;
120 StackFrame.AddrFrame.Offset = Context.Ebp;
121 StackFrame.AddrFrame.Mode = AddrModeFlat;
122 StackFrame.AddrStack.Offset = Context.Esp;
123 StackFrame.AddrStack.Mode = AddrModeFlat;
125 MachineType = IMAGE_FILE_MACHINE_AMD64;
126 StackFrame.AddrPC.Offset = Context.Rip;
127 StackFrame.AddrPC.Mode = AddrModeFlat;
128 StackFrame.AddrFrame.Offset = Context.Rsp;
129 StackFrame.AddrFrame.Mode = AddrModeFlat;
130 StackFrame.AddrStack.Offset = Context.Rsp;
131 StackFrame.AddrStack.Mode = AddrModeFlat;
133 MachineType = IMAGE_FILE_MACHINE_IA64;
134 StackFrame.AddrPC.Offset = Context.StIIP;
135 StackFrame.AddrPC.Mode = AddrModeFlat;
136 StackFrame.AddrFrame.Offset = Context.IntSp;
137 StackFrame.AddrFrame.Mode = AddrModeFlat;
138 StackFrame.AddrBStore.Offset= Context.RsBSP;
139 StackFrame.AddrBStore.Mode = AddrModeFlat;
140 StackFrame.AddrStack.Offset = Context.IntSp;
141 StackFrame.AddrStack.Mode = AddrModeFlat;
143 #error "Unsupported platform"
146 //EnterCriticalSection(&DbgHelpLock);
148 QFile logFile(filename);
149 logFile.open(QIODevice::Append);
150 QTextStream logStream(&logFile);
152 HANDLE hProcess = GetCurrentProcess();
153 HANDLE hThread = GetCurrentThread();
154 SymInitialize(hProcess, NULL, TRUE);
156 DWORD64 dwDisplacement;
158 ULONG64 buffer[(sizeof(SYMBOL_INFO) +
159 MAX_SYM_NAME*sizeof(TCHAR) +
160 sizeof(ULONG64) - 1) / sizeof(ULONG64)];
161 PSYMBOL_INFO pSymbol = (PSYMBOL_INFO)buffer;
162 pSymbol->SizeOfStruct = sizeof(SYMBOL_INFO);
163 pSymbol->MaxNameLen = MAX_SYM_NAME;
165 IMAGEHLP_MODULE64 mod;
166 mod.SizeOfStruct = sizeof(IMAGEHLP_MODULE64);
168 IMAGEHLP_STACK_FRAME ihsf;
169 ZeroMemory(&ihsf, sizeof(IMAGEHLP_STACK_FRAME));
172 while(StackWalk64(MachineType, hProcess, hThread, &StackFrame, &Context, NULL, NULL, NULL, NULL)) {
176 loadHelpStackFrame(ihsf, StackFrame);
177 if(StackFrame.AddrPC.Offset != 0) { // Valid frame.
179 QString fileName("???");
180 if(SymGetModuleInfo64(hProcess, ihsf.InstructionOffset, &mod)) {
181 fileName = QString(mod.ImageName);
182 int slashPos = fileName.lastIndexOf('\\');
184 fileName = fileName.mid(slashPos + 1);
187 if(SymFromAddr(hProcess, ihsf.InstructionOffset, &dwDisplacement, pSymbol)) {
188 funcName = QString(pSymbol->Name);
190 funcName = QString("0x%1").arg(ihsf.InstructionOffset, 8, 16, QLatin1Char('0'));
193 SymSetContext(hProcess, &ihsf, NULL);
194 SymEnumSymbols(hProcess, 0, NULL, EnumSymbolsCB, (PVOID)¶ms);
196 QString debugLine = QString("#%1 %2 0x%3 %4(%5)").arg(i, 3, 10)
198 .arg(ihsf.InstructionOffset, 8, 16, QLatin1Char('0'))
200 .arg(params.join(", "));
201 // qDebug() << qPrintable(debugLine);
202 logStream << debugLine << '\n';
205 break; // we're at the end.
209 // qDebug() << "List of linked Modules:";
210 logStream << "\n\nList of linked Modules:\n";
211 EnumModulesContext modulesContext(hProcess, logStream);
212 SymEnumerateModules64(hProcess, EnumModulesCB, (PVOID)&modulesContext);
216 #if defined(_M_IX86) && defined(Q_CC_MSVC)
218 #pragma optimize("g", on)