on mutex deadlock, get a backtrace of the thread that we're deadlocked
with
This commit is contained in:
@@ -38,7 +38,7 @@
|
|||||||
|
|
||||||
static HFONT hFontMono = NULL;
|
static HFONT hFontMono = NULL;
|
||||||
|
|
||||||
static void DoSave(const EXCEPTION_POINTERS *pExc);
|
static void DoSave();
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
@@ -52,6 +52,7 @@ extern unsigned long version_num;
|
|||||||
|
|
||||||
|
|
||||||
extern HINSTANCE g_hInstance;
|
extern HINSTANCE g_hInstance;
|
||||||
|
#define BACKTRACE_MAX_SIZE 100
|
||||||
|
|
||||||
// WARNING: This is called from crash-time conditions! No malloc() or new!!!
|
// WARNING: This is called from crash-time conditions! No malloc() or new!!!
|
||||||
|
|
||||||
@@ -69,7 +70,10 @@ static void SpliceProgramPath(char *buf, int bufsiz, const char *fn) {
|
|||||||
strcpy(pszFile, fn);
|
strcpy(pszFile, fn);
|
||||||
}
|
}
|
||||||
|
|
||||||
struct VDDebugInfoContext {
|
struct VDDebugInfoContext
|
||||||
|
{
|
||||||
|
VDDebugInfoContext() { pRVAHeap=NULL; }
|
||||||
|
bool Loaded() const { return pRVAHeap != NULL; }
|
||||||
void *pRawBlock;
|
void *pRawBlock;
|
||||||
|
|
||||||
int nBuildNumber;
|
int nBuildNumber;
|
||||||
@@ -113,9 +117,47 @@ static const struct ExceptionLookup {
|
|||||||
{ NULL },
|
{ NULL },
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static const char *LookupException( DWORD code )
|
||||||
|
{
|
||||||
|
for( int i = 0; exceptions[i].code; ++i )
|
||||||
|
if( exceptions[i].code == code )
|
||||||
|
return exceptions[i].name;
|
||||||
|
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct CrashInfo
|
||||||
|
{
|
||||||
|
char m_CrashReason[256];
|
||||||
|
const void *m_BacktracePointers[BACKTRACE_MAX_SIZE];
|
||||||
|
|
||||||
|
const void *m_AlternateThreadBacktrace[BACKTRACE_MAX_SIZE];
|
||||||
|
|
||||||
|
CrashInfo()
|
||||||
|
{
|
||||||
|
m_CrashReason[0] = 0;
|
||||||
|
m_BacktracePointers[0] = m_AlternateThreadBacktrace[0] = NULL;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
static CrashInfo g_CrashInfo;
|
||||||
|
static void GetReason( const EXCEPTION_RECORD *pRecord, CrashInfo *crash )
|
||||||
|
{
|
||||||
|
// fill out bomb reason
|
||||||
|
const char *reason = LookupException( pRecord->ExceptionCode );
|
||||||
|
|
||||||
|
if( reason == NULL )
|
||||||
|
wsprintf( crash->m_CrashReason, "Crash reason: unknown exception 0x%08lx", pRecord->ExceptionCode );
|
||||||
|
else
|
||||||
|
{
|
||||||
|
strcpy( crash->m_CrashReason, "Crash reason: " );
|
||||||
|
strcat( crash->m_CrashReason, reason );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
long VDDebugInfoLookupRVA(VDDebugInfoContext *pctx, unsigned rva, char *buf, int buflen);
|
long VDDebugInfoLookupRVA(VDDebugInfoContext *pctx, unsigned rva, char *buf, int buflen);
|
||||||
bool VDDebugInfoInitFromMemory(VDDebugInfoContext *pctx, const void *_src);
|
bool VDDebugInfoInitFromMemory(VDDebugInfoContext *pctx, const void *_src);
|
||||||
bool VDDebugInfoInitFromFile(VDDebugInfoContext *pctx, const char *pszFilename);
|
bool VDDebugInfoInitFromFile( VDDebugInfoContext *pctx );
|
||||||
void VDDebugInfoDeinit(VDDebugInfoContext *pctx);
|
void VDDebugInfoDeinit(VDDebugInfoContext *pctx);
|
||||||
|
|
||||||
|
|
||||||
@@ -197,13 +239,14 @@ long __stdcall CrashHandler(EXCEPTION_POINTERS *pExc)
|
|||||||
|
|
||||||
// Attempt to read debug file.
|
// Attempt to read debug file.
|
||||||
|
|
||||||
char buf[1024];
|
VDDebugInfoInitFromFile( &g_debugInfo );
|
||||||
SpliceProgramPath(buf, sizeof buf, "StepMania.vdi");
|
|
||||||
VDDebugInfoInitFromFile(&g_debugInfo, buf);
|
|
||||||
|
|
||||||
/* In case something goes amiss before the user can view the crash
|
/* In case something goes amiss before the user can view the crash
|
||||||
* dump, save it now. */
|
* dump, save it now. */
|
||||||
DoSave(pExc);
|
if( !g_CrashInfo.m_CrashReason[0] )
|
||||||
|
GetReason( pExc->ExceptionRecord, &g_CrashInfo );
|
||||||
|
do_backtrace( g_CrashInfo.m_BacktracePointers, BACKTRACE_MAX_SIZE, GetCurrentProcess(), GetCurrentThread(), pExc->ContextRecord );
|
||||||
|
DoSave();
|
||||||
|
|
||||||
++InHere;
|
++InHere;
|
||||||
|
|
||||||
@@ -231,8 +274,7 @@ long __stdcall CrashHandler(EXCEPTION_POINTERS *pExc)
|
|||||||
GetModuleFileName(NULL, szFullAppPath, MAX_PATH);
|
GetModuleFileName(NULL, szFullAppPath, MAX_PATH);
|
||||||
HINSTANCE handle = LoadLibrary(szFullAppPath);
|
HINSTANCE handle = LoadLibrary(szFullAppPath);
|
||||||
|
|
||||||
DialogBoxParam(handle, MAKEINTRESOURCE(IDD_DISASM_CRASH), NULL,
|
DialogBoxParam(handle, MAKEINTRESOURCE(IDD_DISASM_CRASH), NULL, CrashDlgProc, (LPARAM)pExc);
|
||||||
CrashDlgProc, (LPARAM)pExc);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
VDDebugInfoDeinit(&g_debugInfo);
|
VDDebugInfoDeinit(&g_debugInfo);
|
||||||
@@ -269,43 +311,19 @@ static void Report(HWND hwndList, HANDLE hFile, const char *format, ...) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void ReportReason(HWND hwndReason, HANDLE hFile, const EXCEPTION_POINTERS *const pExc)
|
|
||||||
|
|
||||||
|
static void ReportReason( HWND hwndReason, HANDLE hFile, const CrashInfo *pCrash )
|
||||||
{
|
{
|
||||||
const EXCEPTION_RECORD *const pRecord = (const EXCEPTION_RECORD *)pExc->ExceptionRecord;
|
|
||||||
|
|
||||||
// fill out bomb reason
|
|
||||||
|
|
||||||
const struct ExceptionLookup *pel = exceptions;
|
|
||||||
|
|
||||||
while(pel->code) {
|
|
||||||
if (pel->code == pRecord->ExceptionCode)
|
|
||||||
break;
|
|
||||||
|
|
||||||
++pel;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Unfortunately, EXCEPTION_ACCESS_VIOLATION doesn't seem to provide
|
|
||||||
// us with the read/write flag and virtual address as the docs say...
|
|
||||||
// *sigh*
|
|
||||||
|
|
||||||
char buf[256] = "";
|
|
||||||
|
|
||||||
if (!pel->code)
|
|
||||||
wsprintf( buf, "Crash reason: unknown exception 0x%08lx", pRecord->ExceptionCode );
|
|
||||||
else
|
|
||||||
{
|
|
||||||
strcpy( buf, "Crash reason: " );
|
|
||||||
strcat( buf, pel->name );
|
|
||||||
}
|
|
||||||
|
|
||||||
if( hwndReason )
|
if( hwndReason )
|
||||||
SetWindowText( hwndReason, buf );
|
SetWindowText( hwndReason, pCrash->m_CrashReason );
|
||||||
|
|
||||||
if( hFile )
|
if( hFile )
|
||||||
Report( NULL, hFile, buf );
|
Report( NULL, hFile, pCrash->m_CrashReason );
|
||||||
}
|
}
|
||||||
|
|
||||||
static const char *GetNameFromHeap(const char *heap, int idx) {
|
static const char *GetNameFromHeap(const char *heap, int idx)
|
||||||
|
{
|
||||||
while(idx--)
|
while(idx--)
|
||||||
while(*heap++);
|
while(*heap++);
|
||||||
|
|
||||||
@@ -314,7 +332,8 @@ static const char *GetNameFromHeap(const char *heap, int idx) {
|
|||||||
|
|
||||||
//////////////////////////////////////////////////////////////////////////////
|
//////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
static bool IsValidCall(char *buf, int len) {
|
static bool IsValidCall(char *buf, int len)
|
||||||
|
{
|
||||||
// Permissible CALL sequences that we care about:
|
// Permissible CALL sequences that we care about:
|
||||||
//
|
//
|
||||||
// E8 xx xx xx xx CALL near relative
|
// E8 xx xx xx xx CALL near relative
|
||||||
@@ -450,8 +469,14 @@ void VDDebugInfoDeinit(VDDebugInfoContext *pctx) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool VDDebugInfoInitFromFile(VDDebugInfoContext *pctx, const char *pszFilename)
|
bool VDDebugInfoInitFromFile( VDDebugInfoContext *pctx )
|
||||||
{
|
{
|
||||||
|
if( pctx->Loaded() )
|
||||||
|
return true;
|
||||||
|
|
||||||
|
char pszFilename[1024];
|
||||||
|
SpliceProgramPath(pszFilename, sizeof(pszFilename), "StepMania.vdi");
|
||||||
|
|
||||||
pctx->pRawBlock = NULL;
|
pctx->pRawBlock = NULL;
|
||||||
pctx->pRVAHeap = NULL;
|
pctx->pRVAHeap = NULL;
|
||||||
|
|
||||||
@@ -624,14 +649,19 @@ static bool PointsToValidCall( unsigned long ptr )
|
|||||||
return IsValidCall(buf+7, len);
|
return IsValidCall(buf+7, len);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void do_backtrace( const void **buf, size_t size,
|
void do_backtrace( const void **buf, size_t size,
|
||||||
HANDLE hProcess, HANDLE hThread, const CONTEXT *pContext )
|
HANDLE hProcess, HANDLE hThread, const CONTEXT *pContext )
|
||||||
{
|
{
|
||||||
// Retrieve stack pointers.
|
// Retrieve stack pointers.
|
||||||
const char *pStackBase;
|
const char *pStackBase;
|
||||||
{
|
{
|
||||||
LDT_ENTRY sel;
|
LDT_ENTRY sel;
|
||||||
GetThreadSelectorEntry( hThread, pContext->SegFs, &sel );
|
if( !GetThreadSelectorEntry( hThread, pContext->SegFs, &sel ) )
|
||||||
|
{
|
||||||
|
buf[0] = NULL;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
const NT_TIB *tib = (NT_TIB *) ((sel.HighWord.Bits.BaseHi<<24)+(sel.HighWord.Bits.BaseMid<<16)+sel.BaseLow);
|
const NT_TIB *tib = (NT_TIB *) ((sel.HighWord.Bits.BaseHi<<24)+(sel.HighWord.Bits.BaseMid<<16)+sel.BaseLow);
|
||||||
const NT_TIB *pTib = tib->Self;
|
const NT_TIB *pTib = tib->Self;
|
||||||
pStackBase = (char *)pTib->StackBase;
|
pStackBase = (char *)pTib->StackBase;
|
||||||
@@ -669,10 +699,51 @@ static void do_backtrace( const void **buf, size_t size,
|
|||||||
buf[i++] = NULL;
|
buf[i++] = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void SymLookup( const void *ptr, char *buf )
|
||||||
static bool ReportCrashCallStack( HWND hwnd, HANDLE hFile, const CONTEXT *pContext )
|
|
||||||
{
|
{
|
||||||
if( !g_debugInfo.pRVAHeap )
|
VDDebugInfoInitFromFile( &g_debugInfo );
|
||||||
|
if( !g_debugInfo.Loaded() )
|
||||||
|
{
|
||||||
|
strcpy( buf, "error" );
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
MEMORY_BASIC_INFORMATION meminfo;
|
||||||
|
VirtualQuery( ptr, &meminfo, sizeof meminfo );
|
||||||
|
|
||||||
|
char tmp[512];
|
||||||
|
if( VDDebugInfoLookupRVA(&g_debugInfo, (unsigned int)ptr, tmp, sizeof(tmp)) >= 0 )
|
||||||
|
{
|
||||||
|
wsprintf( buf, "%08p: %s", ptr, Demangle(tmp) );
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
char szName[MAX_PATH];
|
||||||
|
if( !CrashGetModuleBaseName((HMODULE)meminfo.AllocationBase, szName) )
|
||||||
|
strcpy( szName, "???" );
|
||||||
|
|
||||||
|
DWORD64 disp;
|
||||||
|
SYMBOL_INFO *pSymbol = GetSym( (unsigned int)ptr, disp );
|
||||||
|
|
||||||
|
if( pSymbol )
|
||||||
|
{
|
||||||
|
wsprintf( buf, "%08lx: %s!%s [%08lx+%lx+%lx]",
|
||||||
|
(unsigned long) ptr, szName, pSymbol->Name,
|
||||||
|
(unsigned long) meminfo.AllocationBase,
|
||||||
|
(unsigned long) (pSymbol->Address) - (unsigned long) (meminfo.AllocationBase),
|
||||||
|
(unsigned long) disp);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
wsprintf( buf, "%08lx: %s!%08lx",
|
||||||
|
(unsigned long) ptr, szName,
|
||||||
|
(unsigned long) meminfo.AllocationBase );
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool ReportCallStack( HWND hwnd, HANDLE hFile, const void **Backtrace )
|
||||||
|
{
|
||||||
|
VDDebugInfoInitFromFile( &g_debugInfo );
|
||||||
|
if( !g_debugInfo.Loaded() )
|
||||||
{
|
{
|
||||||
Report(hwnd, hFile, "Could not open debug resource file (StepMania.vdi).");
|
Report(hwnd, hFile, "Could not open debug resource file (StepMania.vdi).");
|
||||||
return false;
|
return false;
|
||||||
@@ -680,44 +751,15 @@ static bool ReportCrashCallStack( HWND hwnd, HANDLE hFile, const CONTEXT *pConte
|
|||||||
|
|
||||||
if( g_debugInfo.nBuildNumber != int(version_num) )
|
if( g_debugInfo.nBuildNumber != int(version_num) )
|
||||||
{
|
{
|
||||||
Report(hwnd, hFile, "Incorrect StepMania.vdi file (build %d, expected %d) for this version of StepMania -- call stack unavailable.", g_debugInfo.nBuildNumber, int(version_num));
|
Report(hwnd, hFile, "Incorrect StepMania.vdi file (build %d, expected %d) for this version of " PRODUCT_NAME " -- call stack unavailable.", g_debugInfo.nBuildNumber, int(version_num));
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
#define BACKTRACE_MAX_SIZE 100
|
for( int i = 0; Backtrace[i]; ++i )
|
||||||
static const void *BacktracePointers[BACKTRACE_MAX_SIZE];
|
|
||||||
do_backtrace( BacktracePointers, BACKTRACE_MAX_SIZE, GetCurrentProcess(), GetCurrentThread(), pContext );
|
|
||||||
|
|
||||||
for( int i = 0; BacktracePointers[i]; ++i )
|
|
||||||
{
|
{
|
||||||
MEMORY_BASIC_INFORMATION meminfo;
|
char buf[10240];
|
||||||
VirtualQuery( BacktracePointers[i], &meminfo, sizeof meminfo );
|
SymLookup( Backtrace[i], buf );
|
||||||
|
Report( hwnd, hFile, "%s", buf );
|
||||||
char buf[512];
|
|
||||||
if( VDDebugInfoLookupRVA(&g_debugInfo, (unsigned int)BacktracePointers[i], buf, sizeof(buf)) >= 0 )
|
|
||||||
{
|
|
||||||
Report(hwnd, hFile, "%08p: %s", BacktracePointers[i], Demangle(buf));
|
|
||||||
} else {
|
|
||||||
char szName[MAX_PATH];
|
|
||||||
if( !CrashGetModuleBaseName((HMODULE)meminfo.AllocationBase, szName) )
|
|
||||||
strcpy( szName, "???" );
|
|
||||||
|
|
||||||
DWORD64 disp;
|
|
||||||
SYMBOL_INFO *pSymbol = GetSym( (unsigned int)BacktracePointers[i], disp );
|
|
||||||
|
|
||||||
if( pSymbol )
|
|
||||||
{
|
|
||||||
Report(hwnd, hFile, "%08lx: %s!%s [%08lx+%lx+%lx]",
|
|
||||||
(unsigned long) BacktracePointers[i], szName, pSymbol->Name,
|
|
||||||
(unsigned long) meminfo.AllocationBase,
|
|
||||||
(unsigned long) (pSymbol->Address) - (unsigned long) (meminfo.AllocationBase),
|
|
||||||
(unsigned long) disp);
|
|
||||||
} else {
|
|
||||||
Report(hwnd, hFile, "%08lx: %s!%08lx",
|
|
||||||
(unsigned long) BacktracePointers[i], szName,
|
|
||||||
(unsigned long) meminfo.AllocationBase );
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
@@ -729,7 +771,7 @@ void WriteBuf( HANDLE hFile, const char *buf )
|
|||||||
WriteFile(hFile, buf, strlen(buf), &dwActual, NULL);
|
WriteFile(hFile, buf, strlen(buf), &dwActual, NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void DoSave(const EXCEPTION_POINTERS *pExc)
|
static void DoSave()
|
||||||
{
|
{
|
||||||
char szModName2[MAX_PATH];
|
char szModName2[MAX_PATH];
|
||||||
|
|
||||||
@@ -744,16 +786,25 @@ static void DoSave(const EXCEPTION_POINTERS *pExc)
|
|||||||
"--------------------------------------"
|
"--------------------------------------"
|
||||||
"\r\n", PRODUCT_NAME_VER, version_num);
|
"\r\n", PRODUCT_NAME_VER, version_num);
|
||||||
|
|
||||||
ReportReason(NULL, hFile, pExc);
|
ReportReason( NULL, hFile, &g_CrashInfo );
|
||||||
Report(NULL, hFile, "");
|
Report(NULL, hFile, "");
|
||||||
|
|
||||||
// Dump thread stacks
|
// Dump thread stacks
|
||||||
WriteBuf( hFile, Checkpoints::GetLogs("\r\n") );
|
WriteBuf( hFile, Checkpoints::GetLogs("\r\n") );
|
||||||
Report(NULL, hFile, "");
|
Report(NULL, hFile, "");
|
||||||
|
|
||||||
ReportCrashCallStack( NULL, hFile, pExc->ContextRecord );
|
ReportCallStack( NULL, hFile, g_CrashInfo.m_BacktracePointers );
|
||||||
Report(NULL, hFile, "");
|
Report(NULL, hFile, "");
|
||||||
|
|
||||||
|
if( g_CrashInfo.m_AlternateThreadBacktrace[0] )
|
||||||
|
{
|
||||||
|
Report( NULL, hFile, "Deadlocked with:" );
|
||||||
|
Report( NULL, hFile, "" );
|
||||||
|
|
||||||
|
ReportCallStack( NULL, hFile, g_CrashInfo.m_AlternateThreadBacktrace );
|
||||||
|
Report(NULL, hFile, "");
|
||||||
|
}
|
||||||
|
|
||||||
Report(NULL, hFile, "Static log:");
|
Report(NULL, hFile, "Static log:");
|
||||||
WriteBuf( hFile, RageLog::GetInfo() );
|
WriteBuf( hFile, RageLog::GetInfo() );
|
||||||
WriteBuf( hFile, RageLog::GetAdditionalLog() );
|
WriteBuf( hFile, RageLog::GetAdditionalLog() );
|
||||||
@@ -796,89 +847,87 @@ void ViewWithNotepad(const char *str)
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
BOOL APIENTRY CrashDlgProc(HWND hDlg, UINT msg, WPARAM wParam, LPARAM lParam) {
|
BOOL APIENTRY CrashDlgProc(HWND hDlg, UINT msg, WPARAM wParam, LPARAM lParam)
|
||||||
static const EXCEPTION_POINTERS *s_pExc;
|
{
|
||||||
static bool s_bHaveCallstack;
|
static bool s_bHaveCallstack;
|
||||||
|
|
||||||
switch(msg) {
|
switch(msg)
|
||||||
|
{
|
||||||
|
case WM_INITDIALOG:
|
||||||
|
{
|
||||||
|
HWND hwndList = GetDlgItem(hDlg, IDC_CALL_STACK);
|
||||||
|
HWND hwndReason = GetDlgItem(hDlg, IDC_STATIC_BOMBREASON);
|
||||||
|
|
||||||
case WM_INITDIALOG:
|
if (hFontMono)
|
||||||
{
|
SendMessage(hwndList, WM_SETFONT, (WPARAM)hFontMono, MAKELPARAM(TRUE, 0));
|
||||||
HWND hwndList = GetDlgItem(hDlg, IDC_CALL_STACK);
|
|
||||||
HWND hwndReason = GetDlgItem(hDlg, IDC_STATIC_BOMBREASON);
|
|
||||||
const EXCEPTION_POINTERS *const pExc = (const EXCEPTION_POINTERS *)lParam;
|
|
||||||
|
|
||||||
s_pExc = pExc;
|
ReportReason( hwndReason, NULL, &g_CrashInfo );
|
||||||
|
s_bHaveCallstack = ReportCallStack( hwndList, NULL, g_CrashInfo.m_BacktracePointers );
|
||||||
|
}
|
||||||
|
return TRUE;
|
||||||
|
|
||||||
if (hFontMono)
|
case WM_COMMAND:
|
||||||
SendMessage(hwndList, WM_SETFONT, (WPARAM)hFontMono, MAKELPARAM(TRUE, 0));
|
switch(LOWORD(wParam)) {
|
||||||
|
case IDC_BUTTON_CLOSE:
|
||||||
ReportReason(hwndReason, NULL, pExc);
|
EndDialog(hDlg, FALSE);
|
||||||
s_bHaveCallstack = ReportCrashCallStack( hwndList, NULL, pExc->ContextRecord );
|
|
||||||
}
|
|
||||||
return TRUE;
|
return TRUE;
|
||||||
|
case IDOK:
|
||||||
case WM_COMMAND:
|
// EndDialog(hDlg, TRUE); /* don't always exit on ENTER */
|
||||||
switch(LOWORD(wParam)) {
|
return TRUE;
|
||||||
case IDC_BUTTON_CLOSE:
|
case IDC_VIEW_LOG:
|
||||||
EndDialog(hDlg, FALSE);
|
ViewWithNotepad("../log.txt");
|
||||||
return TRUE;
|
|
||||||
case IDOK:
|
|
||||||
// EndDialog(hDlg, TRUE); /* don't always exit on ENTER */
|
|
||||||
return TRUE;
|
|
||||||
case IDC_VIEW_LOG:
|
|
||||||
ViewWithNotepad("../log.txt");
|
|
||||||
break;
|
|
||||||
case IDC_CRASH_SAVE:
|
|
||||||
if (!s_bHaveCallstack)
|
|
||||||
if (IDOK != MessageBox(hDlg,
|
|
||||||
PRODUCT_NAME " cannot load its crash resource file, and thus the crash dump will be "
|
|
||||||
"missing the most important part, the call stack. Crash dumps are much less useful "
|
|
||||||
"without the call stack.",
|
|
||||||
PRODUCT_NAME " warning", MB_OK|MB_ICONEXCLAMATION))
|
|
||||||
return TRUE;
|
|
||||||
|
|
||||||
ViewWithNotepad("../crashinfo.txt");
|
|
||||||
return TRUE;
|
|
||||||
case IDC_BUTTON_RESTART:
|
|
||||||
{
|
|
||||||
char cwd[MAX_PATH];
|
|
||||||
SpliceProgramPath(cwd, MAX_PATH, "");
|
|
||||||
|
|
||||||
TCHAR szFullAppPath[MAX_PATH];
|
|
||||||
GetModuleFileName(NULL, szFullAppPath, MAX_PATH);
|
|
||||||
|
|
||||||
// Launch StepMania
|
|
||||||
PROCESS_INFORMATION pi;
|
|
||||||
STARTUPINFO si;
|
|
||||||
ZeroMemory( &si, sizeof(si) );
|
|
||||||
|
|
||||||
CreateProcess(
|
|
||||||
NULL, // pointer to name of executable module
|
|
||||||
szFullAppPath, // pointer to command line string
|
|
||||||
NULL, // process security attributes
|
|
||||||
NULL, // thread security attributes
|
|
||||||
false, // handle inheritance flag
|
|
||||||
0, // creation flags
|
|
||||||
NULL, // pointer to new environment block
|
|
||||||
cwd, // pointer to current directory name
|
|
||||||
&si, // pointer to STARTUPINFO
|
|
||||||
&pi // pointer to PROCESS_INFORMATION
|
|
||||||
);
|
|
||||||
}
|
|
||||||
EndDialog( hDlg, FALSE );
|
|
||||||
break;
|
|
||||||
case IDC_BUTTON_REPORT:
|
|
||||||
GotoURL( "http://sourceforge.net/tracker/?func=add&group_id=37892&atid=421366" );
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
break;
|
break;
|
||||||
|
case IDC_CRASH_SAVE:
|
||||||
|
if (!s_bHaveCallstack)
|
||||||
|
if (IDOK != MessageBox(hDlg,
|
||||||
|
PRODUCT_NAME " cannot load its crash resource file, and thus the crash dump will be "
|
||||||
|
"missing the most important part, the call stack. Crash dumps are much less useful "
|
||||||
|
"without the call stack.",
|
||||||
|
PRODUCT_NAME " warning", MB_OK|MB_ICONEXCLAMATION))
|
||||||
|
return TRUE;
|
||||||
|
|
||||||
|
ViewWithNotepad("../crashinfo.txt");
|
||||||
|
return TRUE;
|
||||||
|
case IDC_BUTTON_RESTART:
|
||||||
|
{
|
||||||
|
char cwd[MAX_PATH];
|
||||||
|
SpliceProgramPath(cwd, MAX_PATH, "");
|
||||||
|
|
||||||
|
TCHAR szFullAppPath[MAX_PATH];
|
||||||
|
GetModuleFileName(NULL, szFullAppPath, MAX_PATH);
|
||||||
|
|
||||||
|
// Launch StepMania
|
||||||
|
PROCESS_INFORMATION pi;
|
||||||
|
STARTUPINFO si;
|
||||||
|
ZeroMemory( &si, sizeof(si) );
|
||||||
|
|
||||||
|
CreateProcess(
|
||||||
|
NULL, // pointer to name of executable module
|
||||||
|
szFullAppPath, // pointer to command line string
|
||||||
|
NULL, // process security attributes
|
||||||
|
NULL, // thread security attributes
|
||||||
|
false, // handle inheritance flag
|
||||||
|
0, // creation flags
|
||||||
|
NULL, // pointer to new environment block
|
||||||
|
cwd, // pointer to current directory name
|
||||||
|
&si, // pointer to STARTUPINFO
|
||||||
|
&pi // pointer to PROCESS_INFORMATION
|
||||||
|
);
|
||||||
|
}
|
||||||
|
EndDialog( hDlg, FALSE );
|
||||||
|
break;
|
||||||
|
case IDC_BUTTON_REPORT:
|
||||||
|
GotoURL( "http://sourceforge.net/tracker/?func=add&group_id=37892&atid=421366" );
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
return FALSE;
|
return FALSE;
|
||||||
}
|
}
|
||||||
|
|
||||||
void debug_crash() {
|
void NORETURN debug_crash()
|
||||||
|
{
|
||||||
__try {
|
__try {
|
||||||
__asm xor ebx,ebx
|
__asm xor ebx,ebx
|
||||||
__asm mov eax,dword ptr [ebx]
|
__asm mov eax,dword ptr [ebx]
|
||||||
@@ -887,3 +936,34 @@ void debug_crash() {
|
|||||||
} __except(CrashHandler((EXCEPTION_POINTERS*)_exception_info())) {
|
} __except(CrashHandler((EXCEPTION_POINTERS*)_exception_info())) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Get a stack trace of the current thread and the specified thread. */
|
||||||
|
void NORETURN Crash_BacktraceThread( HANDLE hThread )
|
||||||
|
{
|
||||||
|
if( GetThreadId( hThread ) == GetCurrentThreadId() )
|
||||||
|
{
|
||||||
|
/* hThread is the current thread. This shouldn't happen. */
|
||||||
|
strcpy( g_CrashInfo.m_CrashReason, "Crash reason: Thread deadlock (with the current thread?)" );
|
||||||
|
debug_crash();
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Suspend the other thread we're going to backtrace. (We need to at least suspend
|
||||||
|
* hThread, for GetThreadContext to work.) */
|
||||||
|
RageThread::HaltAllThreads( false );
|
||||||
|
// SuspendThread( hThread );
|
||||||
|
|
||||||
|
CONTEXT context;
|
||||||
|
context.ContextFlags = CONTEXT_FULL;
|
||||||
|
if( !GetThreadContext( hThread, &context ) )
|
||||||
|
{
|
||||||
|
strcpy( g_CrashInfo.m_CrashReason, "Crash reason: Thread deadlock (GetThreadContext failed)" );
|
||||||
|
debug_crash();
|
||||||
|
}
|
||||||
|
|
||||||
|
static const void *BacktracePointers[BACKTRACE_MAX_SIZE];
|
||||||
|
do_backtrace( g_CrashInfo.m_AlternateThreadBacktrace, BACKTRACE_MAX_SIZE, GetCurrentProcess(), hThread, &context );
|
||||||
|
|
||||||
|
strcpy( g_CrashInfo.m_CrashReason, "Crash reason: Thread deadlock" );
|
||||||
|
debug_crash();
|
||||||
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -15,13 +15,17 @@
|
|||||||
// along with this program; if not, write to the Free Software
|
// along with this program; if not, write to the Free Software
|
||||||
// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||||
|
|
||||||
#ifndef f_CRASH_H
|
#ifndef CRASH_H
|
||||||
#define f_CRASH_H
|
#define CRASH_H
|
||||||
|
#include <windows.h>
|
||||||
extern long __stdcall CrashHandler(struct _EXCEPTION_POINTERS *ExceptionInfo);
|
extern long __stdcall CrashHandler(struct _EXCEPTION_POINTERS *ExceptionInfo);
|
||||||
|
|
||||||
/* Exactly as advertised. (This will bring up the crash handler even
|
/* Exactly as advertised. (This will bring up the crash handler even
|
||||||
* in the debugger.) */
|
* in the debugger.) */
|
||||||
void debug_crash();
|
void NORETURN debug_crash();
|
||||||
|
|
||||||
|
void do_backtrace( const void **buf, size_t size, HANDLE hProcess, HANDLE hThread, const CONTEXT *pContext );
|
||||||
|
void SymLookup( const void *ptr, char *buf );
|
||||||
|
void NORETURN Crash_BacktraceThread( HANDLE hThread );
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
Reference in New Issue
Block a user