// CCrashDlg message handlers BOOL CCrashDlg :: OnInitDialog ( ) { CDialog::OnInitDialog ( ) ; ASSERT ( NULL != m_pExptPtrs ) ; LPCTSTR szStr = GetFaultReason ( m_pExptPtrs ) ; m_cFaultReason.SetWindowText ( szStr ) ; szStr = GetRegisterString ( m_pExptPtrs ) ; m_cRegisters.SetWindowText ( szStr ) ; szStr = GetFirstStackTraceString ( GSTSO_MODULE | GSTSO_SYMBOL | GSTSO_SRCLINE , m_pExptPtrs ) ; while ( NULL != szStr ) { m_cCallStackList.AddString ( szStr ) ; szStr = GetNextStackTraceString ( GSTSO_MODULE | GSTSO_SYMBOL | GSTSO_SRCLINE , m_pExptPtrs ) ; } if ( FALSE == IsMiniDumpFunctionAvailable ( ) ) { m_cMiniDumpBtn.EnableWindow ( FALSE ) ; } return ( FALSE ) ; }
BSUMDRET __stdcall CreateCurrentProcessMiniDumpW ( MINIDUMP_TYPE eType , wchar_t * szFileName , DWORD dwThread , EXCEPTION_POINTERS * pExceptInfo ) { // Check the string parameter because I am paranoid. I can't check // the eType as that might change in the future. ASSERT ( FALSE == IsBadStringPtrW ( szFileName , MAX_PATH ) ) ; if ( TRUE == IsBadStringPtrW ( szFileName , MAX_PATH ) ) { return ( eBAD_PARAM ) ; } // If an exception pointer blob was passed in. if ( NULL != pExceptInfo ) { ASSERT ( FALSE == IsBadReadPtr ( pExceptInfo , sizeof ( EXCEPTION_POINTERS))); if ( TRUE == IsBadReadPtr ( pExceptInfo , sizeof ( EXCEPTION_POINTERS))) { return ( eBAD_PARAM ) ; } } // Have I even tried to get the exported MiniDumpWriteDump function // yet? if ( ( NULL == g_pfnMDWD ) && ( eINVALID_ERROR == g_eIMDALastError)) { if ( FALSE == IsMiniDumpFunctionAvailable ( ) ) { return ( g_eIMDALastError ) ; } } // If the MiniDumpWriteDump function pointer is NULL, return // whatever was in g_eIMDALastError. if ( NULL == g_pfnMDWD ) { return ( g_eIMDALastError ) ; } // Package up the data for the dump writer thread. DUMPTHREADPARAMS stParams ; stParams.eReturnValue = eINVALID_ERROR ; stParams.eType = eType ; stParams.pExceptInfo = pExceptInfo ; stParams.dwThreadID = dwThread ; stParams.szFileName = szFileName ; stParams.dwMiniDumpWriteDumpLastError = ERROR_SUCCESS ; // Crank the writer thread. DWORD dwTID ; HANDLE hThread = (HANDLE)CreateThread ( NULL , 0 , DumpThread , &stParams , 0 , &dwTID ) ; ASSERT ( (HANDLE)-1 != hThread ) ; if ( (HANDLE)-1 != hThread ) { // The thread is running. Block until the thread ends. WaitForSingleObject ( hThread , INFINITE ) ; // Close the handle. VERIFY ( CloseHandle ( hThread ) ) ; } else { stParams.dwMiniDumpWriteDumpLastError = GetLastError ( ) ; stParams.eReturnValue = eDEATH_ERROR ; } // Set the last error code based so it looks like this thread made // the call to MiniDumpWriteDump. SetLastError ( stParams.dwMiniDumpWriteDumpLastError ) ; return ( stParams.eReturnValue ) ; }
BSUMDRET CommonSnapCurrentProcessMiniDump ( MINIDUMP_TYPE eType , LPCWSTR szDumpName , PCONTEXT pCtx ) { // Assume the best. BSUMDRET eRet = eDUMP_SUCCEEDED ; // Have I even tried to get the exported MiniDumpWriteDump function // yet? if ( ( NULL == g_pfnMDWD ) && ( eINVALID_ERROR == g_eIMDALastError)) { if ( FALSE == IsMiniDumpFunctionAvailable ( ) ) { eRet = g_eIMDALastError ; } } // If the MiniDumpWriteDump function pointer is NULL, I'm done. if ( NULL == g_pfnMDWD ) { eRet = g_eIMDALastError ; } if ( eDUMP_SUCCEEDED == eRet ) { // Armed with the context at the time of the call to this // function, I can now look to actually writing the dump. To // make everything work, I need to make it look like an // exception happened. Hence, all this work to fill out the // MINIDUMP_EXCEPTION_INFORMATION structure. EXCEPTION_RECORD stExRec ; EXCEPTION_POINTERS stExpPtrs ; MINIDUMP_EXCEPTION_INFORMATION stExInfo ; // Zero out all the individual values. ZeroMemory ( &stExRec , sizeof ( EXCEPTION_RECORD )) ; ZeroMemory ( &stExpPtrs , sizeof ( EXCEPTION_POINTERS ) ) ; ZeroMemory ( &stExInfo ,sizeof(MINIDUMP_EXCEPTION_INFORMATION)); // Set the exception address to the start of the CALL // instruction. Interestingly, I found I didn't have to set the // exception code. When you open up a .DMP file created with // this code in VS.NET, you'll see the exception code reported // as: 0x00000000: The operation completed successfully. // warning C4312: 'type cast' : conversion from 'DWORD' // to 'PVOID' of greater size #pragma warning ( disable : 4312 ) stExRec.ExceptionAddress = (PVOID)(pCtx->Eip) ; #pragma warning ( default : 4312 ) // Set the exception pointers. stExpPtrs.ContextRecord = pCtx ; stExpPtrs.ExceptionRecord = &stExRec ; // Finally, set up the exception info structure. stExInfo.ThreadId = GetCurrentThreadId ( ) ; stExInfo.ClientPointers = TRUE ; stExInfo.ExceptionPointers = &stExpPtrs ; // Create the file to write. HANDLE hFile = CreateFile ( szDumpName , GENERIC_READ | GENERIC_WRITE , FILE_SHARE_READ , NULL , CREATE_ALWAYS , FILE_ATTRIBUTE_NORMAL , NULL ) ; ASSERT ( INVALID_HANDLE_VALUE != hFile ) ; if ( INVALID_HANDLE_VALUE != hFile ) { // Do the dump file. BOOL bRetVal = g_pfnMDWD ( GetCurrentProcess ( ) , GetCurrentProcessId ( ) , hFile , eType , &stExInfo , NULL , NULL ) ; ASSERT ( TRUE == bRetVal ) ; if ( TRUE == bRetVal ) { eRet = eDUMP_SUCCEEDED ; } else { eRet = eMINIDUMPWRITEDUMP_FAILED ; } // Close the file. VERIFY ( CloseHandle ( hFile ) ) ; } else { eRet = eOPEN_DUMP_FAILED ; } } return ( eRet ) ; }
BSUMDRET BUGSUTIL_DLLINTERFACE __stdcall CreateCurrentProcessCrashDumpW ( MINIDUMP_TYPE eType , wchar_t * szFileName , DWORD dwThread , EXCEPTION_POINTERS * pExceptInfo ) { // Holds the return value. BSUMDRET eReturnVal = eOPEN_DUMP_FAILED ; // Check the string parameter because I am paranoid. I can't check // the eType as that might change in the future. ASSERT ( FALSE == IsBadStringPtrW ( szFileName , MAX_PATH ) ) ; if ( TRUE == IsBadStringPtrW ( szFileName , MAX_PATH ) ) { return ( eBAD_PARAM ) ; } ASSERT ( FALSE == IsBadReadPtr ( pExceptInfo , sizeof ( EXCEPTION_POINTERS*))); if ( TRUE == IsBadReadPtr ( pExceptInfo , sizeof ( EXCEPTION_POINTERS*))) { return ( eBAD_PARAM ) ; } ASSERT ( 0 != dwThread ) ; if ( 0 == dwThread ) { return ( eBAD_PARAM ) ; } // Have I even tried to get the exported MiniDumpWriteDump function // yet? if ( ( NULL == g_pfnMDWD ) && ( eINVALID_ERROR == g_eIMDALastError)) { if ( FALSE == IsMiniDumpFunctionAvailable ( ) ) { return ( g_eIMDALastError ) ; } } // If the MiniDumpWriteDump function pointer is NULL, return // whatever was in g_eIMDALastError. if ( NULL == g_pfnMDWD ) { return ( g_eIMDALastError ) ; } // Create the file first. HANDLE hFile = CreateFileW ( szFileName , GENERIC_READ | GENERIC_WRITE , 0 , NULL , CREATE_ALWAYS , FILE_ATTRIBUTE_NORMAL , NULL ) ; ASSERT ( INVALID_HANDLE_VALUE != hFile ) ; if ( INVALID_HANDLE_VALUE != hFile ) { MINIDUMP_EXCEPTION_INFORMATION stMDEI ; stMDEI.ThreadId = dwThread ; stMDEI.ExceptionPointers = pExceptInfo ; stMDEI.ClientPointers = TRUE ; // Got the file open. Write it. BOOL bRet = g_pfnMDWD ( GetCurrentProcess ( ) , GetCurrentProcessId ( ) , hFile , eType , &stMDEI , NULL , NULL ) ; ASSERT ( TRUE == bRet ) ; if ( TRUE == bRet ) { eReturnVal = eDUMP_SUCCEEDED ; } else { // Oops. eReturnVal = eMINIDUMPWRITEDUMP_FAILED ; } // Close the open file. VERIFY ( CloseHandle ( hFile ) ) ; } else { // Could not open the file! eReturnVal = eOPEN_DUMP_FAILED ; } // Always save the last error value so I can set it in the original // thread. g_eIMDALastError = eReturnVal ; return ( eReturnVal ) ; }