Permalink
Browse files

Merge pull request #1285 from wsoltys/minidump

[WIN32] Create minidumps for threads terminated by exceptions
  • Loading branch information...
2 parents ee77d6b + f6f1884 commit c2b9d75d64eba1a241e1c117d3244c950103ac94 @wsoltys wsoltys committed Sep 2, 2012
@@ -27,6 +27,12 @@
#else
#define MEASURE_FUNCTION
#endif
+#include "commons/Exception.h"
+
+// Put this here for easy enable and disable
+#ifndef _DEBUG
+#define XBMC_TRACK_EXCEPTIONS
+#endif
CXBApplicationEx::CXBApplicationEx()
{
@@ -77,7 +83,7 @@ INT CXBApplicationEx::Run(bool renderGUI)
unsigned int frameTime = 0;
const unsigned int noRenderFrameTime = 15; // Simulates ~66fps
-#ifndef _DEBUG
+#ifdef XBMC_TRACK_EXCEPTIONS
BYTE processExceptionCount = 0;
BYTE frameMoveExceptionCount = 0;
BYTE renderExceptionCount = 0;
@@ -93,17 +99,28 @@ INT CXBApplicationEx::Run(bool renderGUI)
//-----------------------------------------
// Animate and render a frame
//-----------------------------------------
-#ifndef _DEBUG
+#ifdef XBMC_TRACK_EXCEPTIONS
try
{
#endif
lastFrameTime = XbmcThreads::SystemClockMillis();
Process();
//reset exception count
-#ifndef _DEBUG
+#ifdef XBMC_TRACK_EXCEPTIONS
processExceptionCount = 0;
}
+ catch (const XbmcCommons::UncheckedException &e)
+ {
+ e.LogThrowMessage("CApplication::Process()");
+ processExceptionCount++;
+ //MAX_EXCEPTION_COUNT exceptions in a row? -> bail out
+ if (processExceptionCount > MAX_EXCEPTION_COUNT)
+ {
+ CLog::Log(LOGERROR, "CApplication::Process(), too many exceptions");
+ throw;
+ }
+ }
catch (...)
{
CLog::Log(LOGERROR, "exception in CApplication::Process()");
@@ -117,16 +134,27 @@ INT CXBApplicationEx::Run(bool renderGUI)
}
#endif
// Frame move the scene
-#ifndef _DEBUG
+#ifdef XBMC_TRACK_EXCEPTIONS
try
{
#endif
if (!m_bStop) FrameMove(true, renderGUI);
//reset exception count
-#ifndef _DEBUG
+#ifdef XBMC_TRACK_EXCEPTIONS
frameMoveExceptionCount = 0;
}
+ catch (const XbmcCommons::UncheckedException &e)
+ {
+ e.LogThrowMessage("CApplication::FrameMove()");
+ frameMoveExceptionCount++;
+ //MAX_EXCEPTION_COUNT exceptions in a row? -> bail out
+ if (frameMoveExceptionCount > MAX_EXCEPTION_COUNT)
+ {
+ CLog::Log(LOGERROR, "CApplication::FrameMove(), too many exceptions");
+ throw;
+ }
+ }
catch (...)
{
CLog::Log(LOGERROR, "exception in CApplication::FrameMove()");
@@ -141,7 +169,7 @@ INT CXBApplicationEx::Run(bool renderGUI)
#endif
// Render the scene
-#ifndef _DEBUG
+#ifdef XBMC_TRACK_EXCEPTIONS
try
{
#endif
@@ -152,11 +180,22 @@ INT CXBApplicationEx::Run(bool renderGUI)
if(frameTime < noRenderFrameTime)
Sleep(noRenderFrameTime - frameTime);
}
-#ifndef _DEBUG
+#ifdef XBMC_TRACK_EXCEPTIONS
//reset exception count
renderExceptionCount = 0;
}
+ catch (const XbmcCommons::UncheckedException &e)
+ {
+ e.LogThrowMessage("CApplication::Render()");
+ renderExceptionCount++;
+ //MAX_EXCEPTION_COUNT exceptions in a row? -> bail out
+ if (renderExceptionCount > MAX_EXCEPTION_COUNT)
+ {
+ CLog::Log(LOGERROR, "CApplication::Render(), too many exceptions");
+ throw;
+ }
+ }
catch (...)
{
CLog::Log(LOGERROR, "exception in CApplication::Render()");
@@ -196,7 +196,6 @@ void CThread::Sleep(unsigned int milliseconds)
void CThread::Action()
{
-
try
{
OnStartup();
@@ -237,7 +236,7 @@ void CThread::Action()
}
catch (...)
{
- LOG(LOGERROR, "%s - thread %s, Unhandled exception caught in thread process, aborting. auto delete: %d", __FUNCTION__, m_ThreadName.c_str(), IsAutoDelete());
+ LOG(LOGERROR, "%s - thread %s, Unhandled exception caught in thread OnExit, aborting. auto delete: %d", __FUNCTION__, m_ThreadName.c_str(), IsAutoDelete());
}
}
@@ -70,6 +70,8 @@ void CThread::SetThreadInfo()
__except(EXCEPTION_EXECUTE_HANDLER)
{
}
+
+ win32_exception::install_handler();
}
ThreadIdentifier CThread::GetCurrentThreadId()
@@ -21,85 +21,167 @@
#include "Win32Exception.h"
#include <eh.h>
+#include <dbghelp.h>
+#include "Util.h"
+#include "WIN32Util.h"
#define LOG if(logger) logger->Log
+typedef BOOL (WINAPI *MINIDUMPWRITEDUMP)(HANDLE hProcess, DWORD dwPid, HANDLE hFile, MINIDUMP_TYPE DumpType,
+ CONST PMINIDUMP_EXCEPTION_INFORMATION ExceptionParam,
+ CONST PMINIDUMP_USER_STREAM_INFORMATION UserStreamParam,
+ CONST PMINIDUMP_CALLBACK_INFORMATION CallbackParam);
+
+std::string win32_exception::mVersion;
+
void win32_exception::install_handler()
{
- _set_se_translator(win32_exception::translate);
+ _set_se_translator(win32_exception::translate);
}
void win32_exception::translate(unsigned code, EXCEPTION_POINTERS* info)
{
- // Windows guarantees that *(info->ExceptionRecord) is valid
- switch (code) {
+ switch (code)
+ {
case EXCEPTION_ACCESS_VIOLATION:
- throw access_violation(*(info->ExceptionRecord));
- break;
+ throw access_violation(info);
+ break;
default:
- throw win32_exception(*(info->ExceptionRecord));
- }
+ throw win32_exception(info);
+ }
}
-win32_exception::win32_exception(const EXCEPTION_RECORD& info, const char* classname) :
- XbmcCommons::Exception(classname ? classname : "win32_exception"),
-mWhat("Win32 exception"), mWhere(info.ExceptionAddress), mCode(info.ExceptionCode)
+win32_exception::win32_exception(EXCEPTION_POINTERS* info, const char* classname) :
+ XbmcCommons::UncheckedException(classname ? classname : "win32_exception"),
+ mWhat("Win32 exception"), mWhere(info->ExceptionRecord->ExceptionAddress), mCode(info->ExceptionRecord->ExceptionCode), mExceptionPointers(info)
{
- switch (info.ExceptionCode) {
- case EXCEPTION_ACCESS_VIOLATION:
- mWhat = "Access violation";
- break;
- case EXCEPTION_FLT_DIVIDE_BY_ZERO:
- case EXCEPTION_INT_DIVIDE_BY_ZERO:
- mWhat = "Division by zero";
- break;
- }
+ // Windows guarantees that *(info->ExceptionRecord) is valid
+ switch (info->ExceptionRecord->ExceptionCode)
+ {
+ case EXCEPTION_ACCESS_VIOLATION:
+ mWhat = "Access violation";
+ break;
+ case EXCEPTION_FLT_DIVIDE_BY_ZERO:
+ case EXCEPTION_INT_DIVIDE_BY_ZERO:
+ mWhat = "Division by zero";
+ break;
+ }
}
void win32_exception::LogThrowMessage(const char *prefix) const
{
if( prefix )
- LOG(LOGERROR, "%s : %s (code:0x%08x) at 0x%08x", prefix, (unsigned int) what(), code(), where());
+ LOG(LOGERROR, "Unhandled exception in %s : %s (code:0x%08x) at 0x%08x", prefix, (unsigned int) what(), code(), where());
else
- LOG(LOGERROR, "%s (code:0x%08x) at 0x%08x", what(), code(), where());
+ LOG(LOGERROR, "Unhandled exception in %s (code:0x%08x) at 0x%08x", what(), code(), where());
+ write_minidump();
}
-access_violation::access_violation(const EXCEPTION_RECORD& info)
-: win32_exception(info,"access_voilation"), mAccessType(Invalid), mBadAddress(0)
+bool win32_exception::write_minidump(EXCEPTION_POINTERS* pEp)
{
- switch(info.ExceptionInformation[0])
- {
- case 0:
- mAccessType = Read;
- break;
- case 1:
- mAccessType = Write;
- break;
- case 8:
- mAccessType = DEP;
- break;
- }
- mBadAddress = reinterpret_cast<win32_exception ::Address>(info.ExceptionInformation[1]);
+ // Create the dump file where the xbmc.exe resides
+ bool returncode = false;
+ CStdString dumpFileName;
+ SYSTEMTIME stLocalTime;
+ GetLocalTime(&stLocalTime);
+
+ dumpFileName.Format("xbmc_crashlog-%s-%04d%02d%02d-%02d%02d%02d.dmp",
+ mVersion.c_str(),
+ stLocalTime.wYear, stLocalTime.wMonth, stLocalTime.wDay,
+ stLocalTime.wHour, stLocalTime.wMinute, stLocalTime.wSecond);
+
+ dumpFileName.Format("%s\\%s", CWIN32Util::GetProfilePath().c_str(), CUtil::MakeLegalFileName(dumpFileName));
+
+ HANDLE hDumpFile = CreateFile(dumpFileName.c_str(), GENERIC_WRITE, 0, 0, CREATE_ALWAYS, 0, 0);
+
+ if (hDumpFile == INVALID_HANDLE_VALUE)
+ {
+ LOG(LOGERROR, "CreateFile '%s' failed with error id %d", dumpFileName.c_str(), GetLastError());
+ goto cleanup;
+ }
+
+ // Load the DBGHELP DLL
+ HMODULE hDbgHelpDll = ::LoadLibrary("DBGHELP.DLL");
+ if (!hDbgHelpDll)
+ {
+ LOG(LOGERROR, "LoadLibrary 'DBGHELP.DLL' failed with error id %d", GetLastError());
+ goto cleanup;
+ }
+
+ MINIDUMPWRITEDUMP pDump = (MINIDUMPWRITEDUMP)::GetProcAddress(hDbgHelpDll, "MiniDumpWriteDump");
+ if (!pDump)
+ {
+ LOG(LOGERROR, "Failed to locate MiniDumpWriteDump with error id %d", GetLastError());
+ goto cleanup;
+ }
+
+ // Initialize minidump structure
+ MINIDUMP_EXCEPTION_INFORMATION mdei;
+ mdei.ThreadId = GetCurrentThreadId();
+ mdei.ExceptionPointers = pEp;
+ mdei.ClientPointers = FALSE;
+
+ // Call the minidump api with normal dumping
+ // We can get more detail information by using other minidump types but the dump file will be
+ // extremely large.
+ BOOL bMiniDumpSuccessful = pDump(GetCurrentProcess(), GetCurrentProcessId(), hDumpFile, MiniDumpNormal, &mdei, 0, NULL);
+ if( !bMiniDumpSuccessful )
+ {
+ LOG(LOGERROR, "MiniDumpWriteDump failed with error id %d", GetLastError());
+ goto cleanup;
+ }
+
+ returncode = true;
+
+cleanup:
+
+ if (hDumpFile != INVALID_HANDLE_VALUE)
+ CloseHandle(hDumpFile);
+
+ if (hDbgHelpDll)
+ FreeLibrary(hDbgHelpDll);
+
+ return returncode;
+}
+
+access_violation::access_violation(EXCEPTION_POINTERS* info) :
+ win32_exception(info,"access_voilation"), mAccessType(Invalid), mBadAddress(0)
+{
+ switch(info->ExceptionRecord->ExceptionInformation[0])
+ {
+ case 0:
+ mAccessType = Read;
+ break;
+ case 1:
+ mAccessType = Write;
+ break;
+ case 8:
+ mAccessType = DEP;
+ break;
+ }
+ mBadAddress = reinterpret_cast<win32_exception ::Address>(info->ExceptionRecord->ExceptionInformation[1]);
}
void access_violation::LogThrowMessage(const char *prefix) const
{
if( prefix )
if( mAccessType == Write)
- LOG(LOGERROR, "%s : %s at 0x%08x: Writing location 0x%08x", prefix, what(), where(), address());
+ LOG(LOGERROR, "Unhandled exception in %s : %s at 0x%08x: Writing location 0x%08x", prefix, what(), where(), address());
else if( mAccessType == Read)
- LOG(LOGERROR, "%s : %s at 0x%08x: Reading location 0x%08x", prefix, what(), where(), address());
+ LOG(LOGERROR, "Unhandled exception in %s : %s at 0x%08x: Reading location 0x%08x", prefix, what(), where(), address());
else if( mAccessType == DEP)
- LOG(LOGERROR, "%s : %s at 0x%08x: DEP violation, location 0x%08x", prefix, what(), where(), address());
+ LOG(LOGERROR, "Unhandled exception in %s : %s at 0x%08x: DEP violation, location 0x%08x", prefix, what(), where(), address());
else
- LOG(LOGERROR, "%s : %s at 0x%08x: unknown access type, location 0x%08x", prefix, what(), where(), address());
+ LOG(LOGERROR, "Unhandled exception in %s : %s at 0x%08x: unknown access type, location 0x%08x", prefix, what(), where(), address());
else
if( mAccessType == Write)
- LOG(LOGERROR, "%s at 0x%08x: Writing location 0x%08x", what(), where(), address());
+ LOG(LOGERROR, "Unhandled exception in %s at 0x%08x: Writing location 0x%08x", what(), where(), address());
else if( mAccessType == Read)
- LOG(LOGERROR, "%s at 0x%08x: Reading location 0x%08x", what(), where(), address());
+ LOG(LOGERROR, "Unhandled exception in %s at 0x%08x: Reading location 0x%08x", what(), where(), address());
else if( mAccessType == DEP)
- LOG(LOGERROR, "%s at 0x%08x: DEP violation, location 0x%08x", what(), where(), address());
+ LOG(LOGERROR, "Unhandled exception in %s at 0x%08x: DEP violation, location 0x%08x", what(), where(), address());
else
- LOG(LOGERROR, "%s at 0x%08x: unknown access type, location 0x%08x", what(), where(), address());
+ LOG(LOGERROR, "Unhandled exception in %s at 0x%08x: unknown access type, location 0x%08x", what(), where(), address());
+
+ write_minidump();
}
@@ -25,23 +25,29 @@
#include <exception>
#include "commons/Exception.h"
-class win32_exception: public XbmcCommons::Exception
+class win32_exception: public XbmcCommons::UncheckedException
{
public:
typedef const void* Address; // OK on Win32 platform
static void install_handler();
+ static void set_version(std::string version) { mVersion = version; };
virtual const char* what() const { return mWhat; };
Address where() const { return mWhere; };
unsigned code() const { return mCode; };
virtual void LogThrowMessage(const char *prefix) const;
+ static bool write_minidump(EXCEPTION_POINTERS* pEp);
protected:
- win32_exception(const EXCEPTION_RECORD& info, const char* classname = NULL);
+ win32_exception(EXCEPTION_POINTERS*, const char* classname = NULL);
static void translate(unsigned code, EXCEPTION_POINTERS* info);
+
+ inline bool write_minidump() const { return write_minidump(mExceptionPointers); };
private:
const char* mWhat;
Address mWhere;
unsigned mCode;
+ EXCEPTION_POINTERS *mExceptionPointers;
+ static std::string mVersion;
};
class access_violation: public win32_exception
@@ -62,5 +68,5 @@ class access_violation: public win32_exception
private:
access_type mAccessType;
Address mBadAddress;
- access_violation(const EXCEPTION_RECORD& info);
+ access_violation(EXCEPTION_POINTERS* info);
};
Oops, something went wrong.

0 comments on commit c2b9d75

Please sign in to comment.