16#include <QCoreApplication>
17#include <QLoggingCategory>
20#include "MiniDumper.h"
22#include "RabbitCommonDir.h"
23#include "RabbitCommonTools.h"
29LPTOP_LEVEL_EXCEPTION_FILTER g_UnhandledException =
nullptr;
31static Q_LOGGING_CATEGORY(log,
"RabbitCommon.CoreDump.QMinDumper")
32const
int MaxNameLen = 256;
33QString PrintStack(struct _EXCEPTION_POINTERS *pException)
38 HANDLE process = NULL;
40 HMODULE hModule = NULL;
44 DWORD64 displacement = 0;
48 QScopedArrayPointer<char> buffer(
new char[
sizeof(SYMBOL_INFO) + MAX_SYM_NAME *
sizeof(TCHAR)]);
49 QScopedArrayPointer<char> name(
new char[MaxNameLen]);
50 QScopedArrayPointer<char> module(
new char[MaxNameLen]);
51 PSYMBOL_INFO pSymbol = (PSYMBOL_INFO)buffer.data();
53 szStack =
"*** Exception 0x" + QString::number(pException->ExceptionRecord->ExceptionCode, 16) +
" occurred ***\n\n";
54 PCONTEXT ctx = pException->ContextRecord;
59 memcpy(&ctxCopy, ctx,
sizeof(CONTEXT));
61 memset(&stack, 0,
sizeof( STACKFRAME ));
63 process = GetCurrentProcess();
64 thread = GetCurrentThread();
67 stack.AddrPC.Offset = (*ctx).Eip;
68 stack.AddrPC.Mode = AddrModeFlat;
69 stack.AddrStack.Offset = (*ctx).Esp;
70 stack.AddrStack.Mode = AddrModeFlat;
71 stack.AddrFrame.Offset = (*ctx).Ebp;
72 stack.AddrFrame.Mode = AddrModeFlat;
75 SymInitialize( process, NULL, TRUE );
77 for( frame = 0; ; frame++ )
83 IMAGE_FILE_MACHINE_AMD64
85 IMAGE_FILE_MACHINE_I386
93 SymFunctionTableAccess,
101 pSymbol->SizeOfStruct =
sizeof(SYMBOL_INFO);
102 pSymbol->MaxNameLen = MAX_SYM_NAME;
103 SymFromAddr(process, ( ULONG64 )stack.AddrPC.Offset, &displacement, pSymbol);
105 QScopedPointer<IMAGEHLP_LINE> line(
new IMAGEHLP_LINE());
106 line->SizeOfStruct =
sizeof(IMAGEHLP_LINE);
109 if (SymGetLineFromAddr(process, stack.AddrPC.Offset, &disp, line.data()))
111 szStack += QString::number(no++) +
" 0x" + QString::number(pSymbol->Address, 16)
112 +
" [" + QString(pSymbol->Name) +
"] in "
113 + QString(line->FileName)
114 +
":" + QString::number(line->LineNumber)
121 lstrcpyA(module.data(),
"");
122 GetModuleHandleEx(GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS
123 | GET_MODULE_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT,
124 (LPCTSTR)(stack.AddrPC.Offset), &hModule);
128 GetModuleFileNameA(hModule, module.data(), MaxNameLen);
130 szStack += QString::number(no++) +
" 0x" + QString::number(pSymbol->Address, 16)
131 +
" [" + QString(pSymbol->Name)
132 +
"] in " +
module.data() + "\n";
135 qCritical(log) << szStack.toStdString().c_str();
139QString CoreDump(
struct _EXCEPTION_POINTERS *pException)
141 QString szPath = CDir::Instance()->GetDirLog() + QDir::separator() +
"Core";
142 if (!QDir(szPath).exists())
144 QDir().mkdir(szPath);
147 QString dumpName = QDir::toNativeSeparators(
148 szPath + QDir::separator()
149 + qApp->applicationName()
150 + QString(
"_%1_%2_%3.dmp")
151 .arg(QDateTime::currentDateTime().toString(
"yyyyMMddhhmmss"))
152 .arg(GetCurrentProcessId())
153 .arg(GetCurrentThreadId())
155 qCritical(log) <<
"The core dump file:" << dumpName;
158 HANDLE hDumpFile = CreateFileW(dumpName.toStdWString().c_str(),
159 GENERIC_READ | GENERIC_WRITE,
160 FILE_SHARE_WRITE | FILE_SHARE_READ,
161 0, CREATE_ALWAYS, 0, 0);
162 if (hDumpFile != INVALID_HANDLE_VALUE)
164 MINIDUMP_EXCEPTION_INFORMATION ExpParam;
165 ExpParam.ThreadId = GetCurrentThreadId();
166 ExpParam.ExceptionPointers = pException;
167 ExpParam.ClientPointers = TRUE;
170 MiniDumpWriteDump(GetCurrentProcess(), GetCurrentProcessId(),
171 hDumpFile, MiniDumpWithDataSegs,
172 pException ? &ExpParam : nullptr, nullptr, nullptr);
173 CloseHandle(hDumpFile);
175 qCritical(log) <<
"Core write file fail.";
180LONG WINAPI AppExceptionCallback(
struct _EXCEPTION_POINTERS *pException)
184 bool bDumpToLogFile =
true;
185 bool bDumpFile =
true;
186 QString szConfigure = CLog::Instance()->GetLogConfigureFile();
187 if(!szConfigure.isEmpty()) {
188 QSettings set(szConfigure, QSettings::IniFormat);
189 bDumpToLogFile = set.value(
"CoreDump/DumpToLogFile",
true).toBool();
190 bDumpFile = set.value(
"CoreDump/DumpFile",
true).toBool();
192 if(!(bDumpFile || bDumpToLogFile))
193 return EXCEPTION_CONTINUE_SEARCH;
195 szStack = PrintStack(pException);
197 dumpName = CoreDump(pException);
200 QString szTitle = QObject::tr(
"Application Error");
202 = QObject::tr(
"I'm Sorry, Application is Crash!") +
"\n\n"
203 + QObject::tr(
"Current path: ") + QDir::currentPath() +
"\n\n";
205 szContent += QObject::tr(
"Dump file: ") + dumpName +
"\n\n";
207 szContent += QObject::tr(
"Log file: ") + RabbitCommon::CLog::Instance()->GetLogFile();
208#ifdef HAVE_RABBITCOMMON_GUI
209 CTools::Instance()->ShowCoreDialog(szTitle, szContent, szStack, dumpName);
212 LONG ret = EXCEPTION_EXECUTE_HANDLER;
213 if(g_UnhandledException) {
214 qCritical(log) <<
"Call system default exception";
215 ret = g_UnhandledException(pException);
217 qCritical(log) <<
"Exception exit:" << ret;
221void EnableMiniDumper()
223 g_UnhandledException = SetUnhandledExceptionFilter(AppExceptionCallback);