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;
60 memcpy(&ctxCopy, ctx,
sizeof(CONTEXT));
62 memset(&stack, 0,
sizeof( STACKFRAME ));
64 process = GetCurrentProcess();
65 thread = GetCurrentThread();
70 stack.AddrPC.Offset = ctxCopy.Pc;
71 stack.AddrPC.Mode = AddrModeFlat;
72 stack.AddrStack.Offset = ctxCopy.Sp;
73 stack.AddrStack.Mode = AddrModeFlat;
74 stack.AddrFrame.Offset = ctxCopy.Fp;
75 stack.AddrFrame.Mode = AddrModeFlat;
76#elif defined(_M_AMD64)
77 stack.AddrPC.Offset = ctxCopy.Rip;
78 stack.AddrPC.Mode = AddrModeFlat;
79 stack.AddrStack.Offset = ctxCopy.Rsp;
80 stack.AddrStack.Mode = AddrModeFlat;
81 stack.AddrFrame.Offset = ctxCopy.Rbp;
82 stack.AddrFrame.Mode = AddrModeFlat;
84 stack.AddrPC.Offset = ctxCopy.Eip;
85 stack.AddrPC.Mode = AddrModeFlat;
86 stack.AddrStack.Offset = ctxCopy.Esp;
87 stack.AddrStack.Mode = AddrModeFlat;
88 stack.AddrFrame.Offset = ctxCopy.Ebp;
89 stack.AddrFrame.Mode = AddrModeFlat;
91#error "Unsupported architecture"
95 SymInitialize(process, NULL, TRUE);
100 machineType = IMAGE_FILE_MACHINE_ARM64;
101#elif defined(_M_AMD64)
102 machineType = IMAGE_FILE_MACHINE_AMD64;
103#elif defined(_M_IX86)
104 machineType = IMAGE_FILE_MACHINE_I386;
107 for( frame = 0; ; frame++ )
118 SymFunctionTableAccess,
123 if( !result || stack.AddrPC.Offset == 0)
break;
126 pSymbol->SizeOfStruct =
sizeof(SYMBOL_INFO);
127 pSymbol->MaxNameLen = MAX_SYM_NAME;
128 if (!SymFromAddr(process, stack.AddrPC.Offset, &displacement, pSymbol)) {
129 szStack += QString::number(no++) +
" 0x" + QString::number(stack.AddrPC.Offset, 16)
130 +
" [Unknown Symbol]\n";
136 QScopedPointer<IMAGEHLP_LINE> line(
new IMAGEHLP_LINE());
137 line->SizeOfStruct =
sizeof(IMAGEHLP_LINE);
140 if (SymGetLineFromAddr(process, stack.AddrPC.Offset, &disp, line.data()))
142 szStack += QString::number(no++) +
" 0x" + QString::number(pSymbol->Address, 16)
143 +
" [" + QString(pSymbol->Name) +
"] in "
144 + QString(line->FileName)
145 +
":" + QString::number(line->LineNumber)
149 QScopedPointer<IMAGEHLP_LINE64> line(
new IMAGEHLP_LINE64());
150 line->SizeOfStruct =
sizeof(IMAGEHLP_LINE64);
152 if (SymGetLineFromAddr64(process, stack.AddrPC.Offset, &disp, line.data())) {
153 szStack += QString::number(no++) +
" 0x" + QString::number(pSymbol->Address, 16)
154 +
" [" + QString::fromUtf8(pSymbol->Name) +
"] in "
155 + QString::fromUtf8(line->FileName)
156 +
":" + QString::number(line->LineNumber)
164 lstrcpyA(module.data(),
"");
165 GetModuleHandleEx(GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS
166 | GET_MODULE_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT,
167 (LPCTSTR)(stack.AddrPC.Offset), &hModule);
171 GetModuleFileNameA(hModule, module.data(), MaxNameLen);
173 szStack += QString::number(no++) +
" 0x" + QString::number(pSymbol->Address, 16)
174 +
" [" + QString(pSymbol->Name)
175 +
"] in " +
module.data() + "\n";
178 qCritical(log) << szStack.toStdString().c_str();
182QString CoreDump(
struct _EXCEPTION_POINTERS *pException)
184 QString szPath = CDir::Instance()->GetDirLog() + QDir::separator() +
"Core";
185 if (!QDir(szPath).exists())
187 QDir().mkdir(szPath);
190 QString dumpName = QDir::toNativeSeparators(
191 szPath + QDir::separator()
192 + qApp->applicationName()
193 + QString(
"_%1_%2_%3.dmp")
194 .arg(QDateTime::currentDateTime().toString(
"yyyyMMddhhmmss"))
195 .arg(GetCurrentProcessId())
196 .arg(GetCurrentThreadId())
198 qCritical(log) <<
"The core dump file:" << dumpName;
201 HANDLE hDumpFile = CreateFileW(dumpName.toStdWString().c_str(),
202 GENERIC_READ | GENERIC_WRITE,
203 FILE_SHARE_WRITE | FILE_SHARE_READ,
204 0, CREATE_ALWAYS, 0, 0);
205 if (hDumpFile != INVALID_HANDLE_VALUE)
207 MINIDUMP_EXCEPTION_INFORMATION ExpParam;
208 ExpParam.ThreadId = GetCurrentThreadId();
209 ExpParam.ExceptionPointers = pException;
210 ExpParam.ClientPointers = TRUE;
213 MiniDumpWriteDump(GetCurrentProcess(), GetCurrentProcessId(),
214 hDumpFile, MiniDumpWithDataSegs,
215 pException ? &ExpParam : nullptr, nullptr, nullptr);
216 CloseHandle(hDumpFile);
218 qCritical(log) <<
"Core write file fail.";
223LONG WINAPI AppExceptionCallback(
struct _EXCEPTION_POINTERS *pException)
227 bool bDumpToLogFile =
true;
228 bool bDumpFile =
true;
229 QString szConfigure = CLog::Instance()->GetLogConfigureFile();
230 if(!szConfigure.isEmpty()) {
231 QSettings set(szConfigure, QSettings::IniFormat);
232 bDumpToLogFile = set.value(
"CoreDump/DumpToLogFile",
true).toBool();
233 bDumpFile = set.value(
"CoreDump/DumpFile",
true).toBool();
235 if(!(bDumpFile || bDumpToLogFile))
236 return EXCEPTION_CONTINUE_SEARCH;
238 szStack = PrintStack(pException);
240 dumpName = CoreDump(pException);
243 QString szTitle = QObject::tr(
"Application Error");
245 = QObject::tr(
"I'm Sorry, Application is Crash!") +
"\n\n"
246 + QObject::tr(
"Current path: ") + QDir::currentPath() +
"\n\n";
248 szContent += QObject::tr(
"Dump file: ") + dumpName +
"\n\n";
250 szContent += QObject::tr(
"Log file: ") + RabbitCommon::CLog::Instance()->GetLogFile();
251#ifdef HAVE_RABBITCOMMON_GUI
252 CTools::Instance()->ShowCoreDialog(szTitle, szContent, szStack, dumpName);
255 LONG ret = EXCEPTION_EXECUTE_HANDLER;
256 if(g_UnhandledException) {
257 qCritical(log) <<
"Call system default exception";
258 ret = g_UnhandledException(pException);
260 qCritical(log) <<
"Exception exit:" << ret;
264void EnableMiniDumper()
266 g_UnhandledException = SetUnhandledExceptionFilter(AppExceptionCallback);