aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorwsoltys <wiso@xbmc.org>2012-09-02 15:39:52 -0700
committerwsoltys <wiso@xbmc.org>2012-09-02 15:39:52 -0700
commitc2b9d75d64eba1a241e1c117d3244c950103ac94 (patch)
treec5ce6a8a6c99aeaa92cc848ed6362ccf02caa558
parentee77d6bb78901bdf1053ab76e424768d4bc7d8a4 (diff)
parentf6f1884a35d6d7294c3d3172fbdd3f041fa29794 (diff)
Merge pull request #1285 from wsoltys/minidump
[WIN32] Create minidumps for threads terminated by exceptions
-rw-r--r--xbmc/XBApplicationEx.cpp53
-rw-r--r--xbmc/threads/Thread.cpp3
-rw-r--r--xbmc/threads/platform/win/ThreadImpl.cpp2
-rw-r--r--xbmc/threads/platform/win/Win32Exception.cpp170
-rw-r--r--xbmc/threads/platform/win/Win32Exception.h12
-rw-r--r--xbmc/win32/XBMC_PC.cpp68
6 files changed, 188 insertions, 120 deletions
diff --git a/xbmc/XBApplicationEx.cpp b/xbmc/XBApplicationEx.cpp
index 0a73343a3e..2e830262f7 100644
--- a/xbmc/XBApplicationEx.cpp
+++ b/xbmc/XBApplicationEx.cpp
@@ -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()");
diff --git a/xbmc/threads/Thread.cpp b/xbmc/threads/Thread.cpp
index 9faac80e5f..91eb02389b 100644
--- a/xbmc/threads/Thread.cpp
+++ b/xbmc/threads/Thread.cpp
@@ -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());
}
}
diff --git a/xbmc/threads/platform/win/ThreadImpl.cpp b/xbmc/threads/platform/win/ThreadImpl.cpp
index 967bff97bc..df084900c3 100644
--- a/xbmc/threads/platform/win/ThreadImpl.cpp
+++ b/xbmc/threads/platform/win/ThreadImpl.cpp
@@ -70,6 +70,8 @@ void CThread::SetThreadInfo()
__except(EXCEPTION_EXECUTE_HANDLER)
{
}
+
+ win32_exception::install_handler();
}
ThreadIdentifier CThread::GetCurrentThreadId()
diff --git a/xbmc/threads/platform/win/Win32Exception.cpp b/xbmc/threads/platform/win/Win32Exception.cpp
index 7f80cba710..d9f3bc425c 100644
--- a/xbmc/threads/platform/win/Win32Exception.cpp
+++ b/xbmc/threads/platform/win/Win32Exception.cpp
@@ -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();
}
diff --git a/xbmc/threads/platform/win/Win32Exception.h b/xbmc/threads/platform/win/Win32Exception.h
index 9b957513e9..53506d48f4 100644
--- a/xbmc/threads/platform/win/Win32Exception.h
+++ b/xbmc/threads/platform/win/Win32Exception.h
@@ -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 @@ protected:
private:
access_type mAccessType;
Address mBadAddress;
- access_violation(const EXCEPTION_RECORD& info);
+ access_violation(EXCEPTION_POINTERS* info);
};
diff --git a/xbmc/win32/XBMC_PC.cpp b/xbmc/win32/XBMC_PC.cpp
index c11a0c1815..9d248058b8 100644
--- a/xbmc/win32/XBMC_PC.cpp
+++ b/xbmc/win32/XBMC_PC.cpp
@@ -23,80 +23,19 @@
#include "settings/AppParamParser.h"
#include "utils/CharsetConverter.h"
#include "utils/log.h"
-#include "WIN32Util.h"
+#include "threads/platform/win/Win32Exception.h"
#include "shellapi.h"
#include "dbghelp.h"
#include "XBDateTime.h"
#include "threads/Thread.h"
#include "Application.h"
#include "XbmcContext.h"
-
-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);
-
+#include "GUIInfoManager.h"
// Minidump creation function
LONG WINAPI CreateMiniDump( EXCEPTION_POINTERS* pEp )
{
- // Create the dump file where the xbmc.exe resides
- CStdString errorMsg;
- CStdString dumpFile;
- CDateTime now(CDateTime::GetCurrentDateTime());
- dumpFile.Format("%s\\xbmc_crashlog-%s-%04i%02i%02i-%02i%02i%02i.dmp", CWIN32Util::GetProfilePath().c_str(), GIT_REV, now.GetYear(), now.GetMonth(), now.GetDay(), now.GetHour(), now.GetMinute(), now.GetSecond());
- HANDLE hFile = CreateFile(dumpFile.c_str(), GENERIC_READ | GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL );
-
- // Call MiniDumpWriteDump api with the dump file
- if ( hFile && ( hFile != INVALID_HANDLE_VALUE ) )
- {
- // Load the DBGHELP DLL
- HMODULE hDbgHelpDll = ::LoadLibrary("DBGHELP.DLL");
- if (hDbgHelpDll)
- {
- MINIDUMPWRITEDUMP pDump = (MINIDUMPWRITEDUMP)::GetProcAddress(hDbgHelpDll, "MiniDumpWriteDump");
- if (pDump)
- {
- // Initialize minidump structure
- MINIDUMP_EXCEPTION_INFORMATION mdei;
- mdei.ThreadId = CThread::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
- // extermely large.
- BOOL rv = pDump(GetCurrentProcess(), GetCurrentProcessId(), hFile, MiniDumpNormal, &mdei, 0, NULL);
- if( !rv )
- {
- errorMsg.Format("MiniDumpWriteDump failed with error id %d", GetLastError());
- MessageBox(NULL, errorMsg.c_str(), "XBMC: Error", MB_OK|MB_ICONERROR);
- }
- }
- else
- {
- errorMsg.Format("MiniDumpWriteDump failed to load with error id %d", GetLastError());
- MessageBox(NULL, errorMsg.c_str(), "XBMC: Error", MB_OK|MB_ICONERROR);
- }
-
- // Close the DLL
- FreeLibrary(hDbgHelpDll);
- }
- else
- {
- errorMsg.Format("LoadLibrary 'DBGHELP.DLL' failed with error id %d", GetLastError());
- MessageBox(NULL, errorMsg.c_str(), "XBMC: Error", MB_OK|MB_ICONERROR);
- }
-
- // Close the file
- CloseHandle( hFile );
- }
- else
- {
- errorMsg.Format("CreateFile '%s' failed with error id %d", dumpFile.c_str(), GetLastError());
- MessageBox(NULL, errorMsg.c_str(), "XBMC: Error", MB_OK|MB_ICONERROR);
- }
-
+ win32_exception::write_minidump(pEp);
return pEp->ExceptionRecord->ExceptionCode;;
}
@@ -121,6 +60,7 @@ INT WINAPI WinMain( HINSTANCE hInst, HINSTANCE, LPSTR commandLine, INT )
CLog::SetLogLevel(g_advancedSettings.m_logLevel);
// Initializes CreateMiniDump to handle exceptions.
+ win32_exception::set_version(g_infoManager.GetVersion());
SetUnhandledExceptionFilter( CreateMiniDump );
// check if XBMC is already running