--- /dev/null
+/***************************************************************************
+ * Copyright (C) 2005-08 by the Quassel IRC Team *
+ * 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"
+
+#if defined(HAVE_EXECINFO) // && !defined(Q_OS_MAC)
+# define BUILD_CRASHHANDLER
+# include <execinfo.h>
+# include <dlfcn.h>
+# include <cxxabi.h>
+# include <QFile>
+# include <QTextStream>
+# include <QDebug>
+#endif
+
+void Quassel::logBacktrace(const QString &filename) {
+#ifndef BUILD_CRASHHANDLER
+ Q_UNUSED(filename)
+#else
+ void* callstack[128];
+ int i, frames = backtrace(callstack, 128);
+
+ QFile dumpFile(filename);
+ dumpFile.open(QIODevice::Append);
+ QTextStream dumpStream(&dumpFile);
+
+ for (i = 0; i < frames; ++i) {
+ Dl_info info;
+ dladdr (callstack[i], &info);
+ // as a reference:
+ // typedef struct
+ // {
+ // __const char *dli_fname; /* File name of defining object. */
+ // void *dli_fbase; /* Load address of that object. */
+ // __const char *dli_sname; /* Name of nearest symbol. */
+ // void *dli_saddr; /* Exact value of nearest symbol. */
+ // } Dl_info;
+
+ #if __LP64__
+ int addrSize = 16;
+ #else
+ int addrSize = 8;
+ #endif
+
+ QString funcName;
+ if(info.dli_sname) {
+ char *func = abi::__cxa_demangle(info.dli_sname, 0, 0, 0);
+ if(func) {
+ funcName = QString(func);
+ free(func);
+ } else {
+ funcName = QString(info.dli_sname);
+ }
+ } else {
+ funcName = QString("0x%1").arg((ulong)(info.dli_saddr), addrSize, 16, QLatin1Char('0'));
+ }
+
+ // prettificating the filename
+ QString fileName("???");
+ if(info.dli_fname) {
+ fileName = QString(info.dli_fname);
+ int slashPos = fileName.lastIndexOf('/');
+ if(slashPos != -1)
+ fileName = fileName.mid(slashPos + 1);
+ }
+
+ QString debugLine = QString("#%1 %2 0x%3 %4").arg(i, 3, 10)
+ .arg(fileName, - 20)
+ .arg((ulong)(callstack[i]), addrSize, 16, QLatin1Char('0'))
+ .arg(funcName);
+
+ dumpStream << debugLine << "\n";
+ qDebug() << qPrintable(debugLine);
+ }
+ dumpFile.close();
+#endif /* BUILD_CRASHHANDLER */
+}
--- /dev/null
+/***************************************************************************\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
#include "types.h"
#include "syncableobject.h"
-#if defined(HAVE_EXECINFO) && !defined(Q_OS_MAC)
-# define BUILD_CRASHHANDLER
-# include <execinfo.h>
-# include <dlfcn.h>
-# include <cxxabi.h>
-#endif
-
Quassel::BuildInfo Quassel::_buildInfo;
CliParser *Quassel::_cliParser = 0;
Quassel::RunMode Quassel::_runMode;
signal(SIGTERM, handleSignal);
signal(SIGINT, handleSignal);
-#ifdef BUILD_CRASHHANDLER
+ // we have crashhandler for win32 and unix (based on execinfo).
+ // on mac os we use it's integrated backtrace generator
+#if defined(Q_OS_WIN32) || (defined(HAVE_EXECINFO) && !defined(Q_OS_MAC))
signal(SIGABRT, handleSignal);
- signal(SIGBUS, handleSignal);
signal(SIGSEGV, handleSignal);
-#endif // #if defined(HAVE_EXECINFO) && !defined(Q_OS_MAC)
+# ifndef Q_OS_WIN32
+ signal(SIGBUS, handleSignal);
+# endif
+#endif
_cliParser = new CliParser();
//! Signal handler for graceful shutdown.
void Quassel::handleSignal(int sig) {
switch(sig) {
- case SIGTERM:
- case SIGINT:
- qWarning("%s", qPrintable(QString("Caught signal %1 - exiting.").arg(sig)));
- QCoreApplication::quit();
- break;
-
-#ifdef BUILD_CRASHHANDLER
- case SIGABRT:
- case SIGBUS:
- case SIGSEGV:
- handleCrash();
+ case SIGTERM:
+ case SIGINT:
+ qWarning("%s", qPrintable(QString("Caught signal %1 - exiting.").arg(sig)));
+ QCoreApplication::quit();
+ break;
+ case SIGABRT:
+ case SIGSEGV:
+#ifndef Q_OS_WIN32
+ case SIGBUS:
#endif
- break;
- default:
- break;
+ logBacktrace(coreDumpFileName());
+ break;
+ default:
+ break;
}
}
void Quassel::logFatalMessage(const char *msg) {
-#ifndef Q_OS_MAC
+#ifdef Q_OS_MAC
+ Q_UNUSED(msg)
+#else
QFile dumpFile(coreDumpFileName());
- dumpFile.open(QIODevice::WriteOnly);
+ dumpFile.open(QIODevice::Append);
QTextStream dumpStream(&dumpFile);
-#else
- QTextStream dumpStream(stderr);
-#endif
dumpStream << "Fatal: " << msg << '\n';
dumpStream.flush();
-
- qInstallMsgHandler(0);
- abort();
-}
-
-void Quassel::handleCrash() {
-#ifdef BUILD_CRASHHANDLER
- void* callstack[128];
- int i, frames = backtrace(callstack, 128);
-
- QFile dumpFile(coreDumpFileName());
- dumpFile.open(QIODevice::Append);
- QTextStream dumpStream(&dumpFile);
-
- dumpStream << "Quassel IRC: " << _buildInfo.baseVersion << ' ' << _buildInfo.commitHash << '\n';
-
- for (i = 0; i < frames; ++i) {
- Dl_info info;
- dladdr (callstack[i], &info);
- // as a reference:
- // typedef struct
- // {
- // __const char *dli_fname; /* File name of defining object. */
- // void *dli_fbase; /* Load address of that object. */
- // __const char *dli_sname; /* Name of nearest symbol. */
- // void *dli_saddr; /* Exact value of nearest symbol. */
- // } Dl_info;
-
- #if __LP64__
- int addrSize = 16;
- #else
- int addrSize = 8;
- #endif
-
- QString funcName;
- if(info.dli_sname) {
- char *func = abi::__cxa_demangle(info.dli_sname, 0, 0, 0);
- if(func) {
- funcName = QString(func);
- free(func);
- } else {
- funcName = QString(info.dli_sname);
- }
- } else {
- funcName = QString("0x%1").arg((long)info.dli_saddr, addrSize, QLatin1Char('0'));
- }
-
- // prettificating the filename
- QString fileName("???");
- if(info.dli_fname) {
- fileName = QString(info.dli_fname);
- int slashPos = fileName.lastIndexOf('/');
- if(slashPos != -1)
- fileName = fileName.mid(slashPos + 1);
- if(fileName.count() < 20)
- fileName += QString(20 - fileName.count(), ' ');
- }
-
- QString debugLine = QString("#%1 %2 0x%3 %4").arg(i, 3, 10)
- .arg(fileName)
- .arg((long)(callstack[i]), addrSize, 16, QLatin1Char('0'))
- .arg(funcName);
-
- dumpStream << debugLine << "\n";
- qDebug() << qPrintable(debugLine);
- }
dumpFile.close();
- exit(27);
-#endif /* BUILD_CRASHHANDLER */
+#endif
}
const QString &Quassel::coreDumpFileName() {
- if(_coreDumpFileName.isEmpty())
+ if(_coreDumpFileName.isEmpty()) {
_coreDumpFileName = QString("Quassel-Crash-%1.log").arg(QDateTime::currentDateTime().toString("yyyyMMdd-hhmm"));
-
+ QFile dumpFile(_coreDumpFileName);
+ dumpFile.open(QIODevice::Append);
+ QTextStream dumpStream(&dumpFile);
+ dumpStream << "Quassel IRC: " << _buildInfo.baseVersion << ' ' << _buildInfo.commitHash << '\n';
+ qDebug() << "Quassel IRC: " << _buildInfo.baseVersion << ' ' << _buildInfo.commitHash;
+ dumpStream.flush();
+ dumpFile.close();
+ }
return _coreDumpFileName;
}