#include "stdafx.h" #include "svcobjdef.h" #include "dbghelp.h" #include "Processes.h" #include "Notify.h" #include "resource.h" CEMSessionThread::CEMSessionThread ( IN PEmObject pEmObj ) { ATLTRACE(_T("CEMSessionThread::CEMSessionThread\n")); m_pEmSessObj = pEmObj; eDBGSessType = SessType_Automatic; m_pDBGClient = NULL; m_pDBGControl = NULL; m_pDBGSymbols = NULL; m_pASTManager = &(_Module.m_SessionManager); m_hEvent = CreateEvent( NULL, FALSE, FALSE, NULL ); m_hCDBStarted = CreateEvent ( NULL, FALSE, FALSE, NULL ); //// - InitAutomaticSession.. m_bRecursive = FALSE; m_bstrEcxFilePath = NULL; m_bstrNotificationString = NULL; m_bstrAltSymPath = NULL; m_bGenerateMiniDump = FALSE; m_bGenerateUserDump = FALSE; //// - InitManualSession.. m_bstrUserName = NULL; m_bstrPassword = NULL; m_nPort = 0; m_bBlockIncomingIPConnections = FALSE; m_bContinueSession = TRUE; m_pEcxFile = NULL; ZeroMemory(&m_sp, sizeof(m_sp)); ZeroMemory(&m_pi, sizeof(m_pi)); }; CEMSessionThread::~CEMSessionThread(){ ATLTRACE(_T("CEMSessionThread::~CEMSessionThread\n")); if(m_bstrUserName) SysFreeString(m_bstrUserName); if(m_bstrPassword) SysFreeString(m_bstrPassword); if(m_pDBGClient) m_pDBGClient->Release(); if(m_pDBGControl) m_pDBGControl->Release(); if(m_pDBGSymbols) m_pDBGSymbols->Release(); if(m_bstrEcxFilePath) ::SysFreeString(m_bstrEcxFilePath); if(m_bstrNotificationString) ::SysFreeString(m_bstrNotificationString ); if(m_bstrAltSymPath) ::SysFreeString(m_bstrAltSymPath); CloseHandle( m_hEvent ); CloseHandle( m_hCDBStarted ); }; DWORD CEMSessionThread::Run ( void ) { ATLTRACE(_T("CEMSessionThread::Run\n")); TCHAR szConnectString[_MAX_PATH] = _T(""); char *szClientConnectString = NULL; DWORD dwLastRet = -1L; HRESULT hr = E_FAIL, hrActual = E_FAIL; EmSessionStatus nStatus = STAT_SESS_NONE_STAT_NONE; UINT nPid = 0; EmObject EmObj; PEMSession pEmSess = NULL; do { do { if( m_pEmSessObj->type == EMOBJ_SERVICE ) { if( (m_pEmSessObj->nStatus == STAT_SESS_NOT_STARTED_NOTRUNNING) || (m_pEmSessObj->nStatus & STAT_SESS_STOPPED) ) { hr = S_OK; do { dwLastRet = StartServiceAndGetPid( m_pEmSessObj->szSecName, &nPid ); if( dwLastRet != ERROR_SERVICE_ALREADY_RUNNING ) { hr = HRESULT_FROM_WIN32(dwLastRet); break; } } while ( false ); FAILEDHR_BREAK(hr); hr = m_pASTManager->GetSession( m_pEmSessObj->guidstream, &pEmSess ); FAILEDHR_BREAK(hr); memcpy((void *)&EmObj, (void *) pEmSess->pEmObj, sizeof EmObject); EmObj.nStatus = STAT_SESS_NOT_STARTED_RUNNING; EmObj.nId = nPid; EmObj.hr = S_OK; hr = m_pASTManager->UpdateSessObject( EmObj.guidstream, &EmObj ); FAILEDHR_BREAK(hr); } } // // Get server connection string and start CDB server // Ex: -server tcp:port=XXX -p YYY // -server npipe:pipe=EM_YYY -p YYY // hr = GetServerConnectString( szConnectString, _MAX_PATH ); if( FAILED(hr) ) { hrActual = hr; nStatus = STAT_SESS_STOPPED_FAILED; break; } hr = StartCDBServer( szConnectString ); // Indicates that the CDB server got started or failed.. SetEvent(m_hCDBStarted); if( FAILED(hr) ) { hrActual = hr; hr = EMERROR_CDBSERVERSTARTFAILED; nStatus = STAT_SESS_STOPPED_FAILED; break; } #ifdef _DEBUG m_pASTManager->SetSessionStatus( m_pEmSessObj->guidstream, STAT_SESS_DEBUG_IN_PROGRESS_NONE, S_OK, L"StartCDBServer Successful" ); #else m_pASTManager->SetSessionStatus( m_pEmSessObj->guidstream, STAT_SESS_DEBUG_IN_PROGRESS_NONE, S_OK, NULL ); #endif // // Get client connection string and start monitoring // Ex: -remote tcp:server=ABCD,port=XXX // -remote npipe:server=ABCD,pipe=EM_YYY // hr = GetClientConnectString( szConnectString, _MAX_PATH ); if( FAILED(hr) ) { hrActual = hr; hr = EMERROR_CDBSERVERSTARTFAILED; nStatus = STAT_SESS_STOPPED_FAILED; break; } size_t Len = wcstombs( NULL, szConnectString, 0 ); szClientConnectString = (char *)calloc(Len+1, sizeof(char)); _ASSERTE( szClientConnectString != NULL ); if( szClientConnectString == NULL ) { hr = HRESULT_FROM_WIN32( GetLastError() ); hrActual = hr; hr = EMERROR_CDBSERVERSTARTFAILED; nStatus = STAT_SESS_STOPPED_FAILED; break; } wcstombs( szClientConnectString, szConnectString, Len ); if( eDBGSessType == SessType_Automatic ){ StartAutomaticExcepMonitoring( szClientConnectString ); } else{ // // Need info.. // StartAutomaticExcepMonitoring( szClientConnectString ); // StartManualExcepMonitoring( szClientConnectString ); } hr = S_OK; } while ( m_bRecursive && m_bContinueSession ); // Need to put in a way of stopping the session. } while( false ); if(FAILED(hr)) { #ifdef _DEBUG m_pASTManager->SetSessionStatus( m_pEmSessObj->guidstream, STAT_SESS_STOPPED_FAILED, hrActual, L"CEMSessionThread::Run - Failed", true, true ); #else m_pASTManager->SetSessionStatus( m_pEmSessObj->guidstream, STAT_SESS_STOPPED_FAILED, hrActual, NULL, true, true ); #endif StopServer(); } if( szClientConnectString != NULL ){ free(szClientConnectString); } return hr; } HRESULT CEMSessionThread::StartAutomaticExcepMonitoring( char *pszConnectString ) { ATLTRACE(_T("CEMSessionThread::StartAutomaticExcepMonitoring\n")); HRESULT hr = E_FAIL, hrActual = E_FAIL; TCHAR szUniqueFileName[_MAX_PATH+1] = _T(""); char szLogFile[_MAX_PATH+1] = ""; TCHAR szLogDir[_MAX_PATH+1] = _T(""); char szEcxFile[_MAX_PATH+1] = ""; TCHAR szEcxDir[_MAX_PATH+1] = _T(""); bool bStop = FALSE; char szCmd[_MAX_PATH+1] = ""; TCHAR szFileExt[_MAX_EXT+1] = _T(""); DWORD dwBufSize = _MAX_PATH; char szAltSymPath[_MAX_PATH+1] = ""; EmSessionStatus nStatus = STAT_SESS_NONE_STAT_NONE; bstr_t bstrStatus; do { _ASSERTE(m_bstrEcxFilePath != NULL); _Module.GetEmDirectory( EMOBJ_CMDSET, szEcxDir, dwBufSize, NULL, NULL ); _stprintf(szEcxDir, _T("%s\\%s"), szEcxDir, m_bstrEcxFilePath); wcstombs( szEcxFile, szEcxDir, dwBufSize ); dwBufSize = _MAX_PATH; _Module.GetEmDirectory( EMOBJ_LOGFILE, szLogDir, dwBufSize, szFileExt, _MAX_EXT ); CreateDirectory( szLogDir, NULL ); GetUniqueFileName( m_pEmSessObj, szUniqueFileName, _T(""), szFileExt, false ); _stprintf(szLogDir, _T("%s\\%s"), szLogDir, szUniqueFileName); wcstombs( szLogFile, szLogDir, dwBufSize ); hr = DebugConnect( pszConnectString, IID_IDebugClient, (void **)&m_pDBGClient ); if( FAILED(hr) ) { hrActual = hr; hr = EMERROR_CONNECTIONTOSERVERFAILED; nStatus = STAT_SESS_STOPPED_FAILED; bstrStatus = L"DebugConnect failed"; break; } #ifdef _DEBUG m_pASTManager->SetSessionStatus( m_pEmSessObj->guidstream, STAT_SESS_DEBUG_IN_PROGRESS_NONE, hr, L"DebugConnect Succeeded.." ); #else m_pASTManager->SetSessionStatus( m_pEmSessObj->guidstream, STAT_SESS_DEBUG_IN_PROGRESS_NONE, hr, NULL ); #endif hr = m_pDBGClient->QueryInterface( IID_IDebugControl, (void **)&m_pDBGControl ); if( FAILED(hr) ) { nStatus = STAT_SESS_STOPPED_FAILED; bstrStatus = L"IDbgClient::QIFace ( IDbgControl ) failed"; break; } hr = m_pDBGClient->QueryInterface( IID_IDebugSymbols, (void **)&m_pDBGSymbols ); if( FAILED(hr) ) { nStatus = STAT_SESS_STOPPED_FAILED; bstrStatus = L"IDbgClient::QIFace ( IDebugSymbols ) failed"; break; } wcstombs( szAltSymPath, m_bstrAltSymPath, dwBufSize ); if( strcmp( szAltSymPath, "" ) != 0 ) { hr = m_pDBGSymbols->SetSymbolPath(szAltSymPath); if( FAILED(hr) ) { hrActual = hr; hr = EMERROR_ALTSYMPATHFAILED; nStatus = STAT_SESS_STOPPED_FAILED; bstrStatus = L"Alternate symbol path could not be set"; break; } } if( eDBGSessType == SessType_Automatic ) { hr = m_pDBGControl->OpenLogFile(szLogFile, FALSE); if( FAILED(hr) ) { hrActual = hr; hr = EMERROR_UNABLETOCREATELOGFILE; nStatus = STAT_SESS_STOPPED_FAILED; bstrStatus = L"Open log file failed"; break; } } /* hr = m_pDBGControl->ExecuteCommandFile( DEBUG_OUTCTL_LOG_ONLY, szEcxFile, DEBUG_EXECUTE_DEFAULT ); if( FAILED(hr) ) { hrActual = hr; hr = EMERROR_ECXFILEEXECUTIONFAILED; nStatus = STAT_SESS_STOPPED_FAILED; bstrStatus = L"ExecCommandFile failed"; break; } */ m_EventCallbacks.m_pEMThread = this; hr = m_pDBGClient->SetEventCallbacks(&m_EventCallbacks); if( FAILED(hr) ) { hrActual = hr; hr = EMERROR_CALLBACKSCANNOTBEREGISTERED; nStatus = STAT_SESS_STOPPED_FAILED; bstrStatus = L"SetEventCallback failed"; break; } ULONG ExecStatus = DEBUG_STATUS_BREAK; if( _tcscmp( m_bstrEcxFilePath, _T("") ) != 0 ) { m_pEcxFile = fopen(szEcxFile, "r"); if( m_pEcxFile == NULL ) { hr = HRESULT_FROM_WIN32(GetLastError()); hrActual = hr; hr = EMERROR_ECXFILEOPENFAILED; nStatus = STAT_SESS_STOPPED_FAILED; bstrStatus = L"fopen failed"; break; } hr = ExecuteCommandsTillGo(NULL); } do { hr = KeepDebuggeeRunning(); if( FAILED(hr) ) { nStatus = STAT_SESS_STOPPED_FAILED; bstrStatus = L"KeepDebugeeRunning failed"; break; } hr = CanContinue(); if( FAILED(hr) ) { nStatus = STAT_SESS_STOPPED_FAILED; bstrStatus = L"Can Continue() failed"; break; } hr = m_pDBGClient->DispatchCallbacks(INFINITE); // Milli Secs.. if( FAILED(hr) ) { hrActual = hr; hr = EMERROR_DISPATCHCALLBACKFAILED; nStatus = STAT_SESS_STOPPED_FAILED; bstrStatus = L"DispatchCallbacks failed"; break; } // // Is this call required??? // hr = CanContinue(); if( hr != S_OK ) { bstrStatus = L"CanContinue hr != S_OK"; break; } hr = BreakIn(); if( FAILED(hr) ) { bstrStatus = L"BreakIn"; nStatus = STAT_SESS_STOPPED_FAILED; break; } if( strcmp( szEcxFile, "" ) != 0 ) { ExecuteCommandsTillGo(NULL); } if( eDBGServie == DBGService_HandleException ) { break; } dwBufSize = _MAX_PATH; hr = GetCmd( eDBGServie, szCmd, dwBufSize ); if( FAILED(hr) ) { nStatus = STAT_SESS_STOPPED_FAILED; bstrStatus = L"GetCmd failed"; break; } /* hr = BreakIn(); if( FAILED(hr) ) { bstrStatus = L"BreakIn"; nStatus = STAT_SESS_STOPPED_FAILED; break; } */ if( strcmp( szCmd, "q" ) == 0 ){ if( eDBGSessType == SessType_Automatic ) { hr = m_pDBGControl->CloseLogFile(); if( FAILED(hr) ) { bstrStatus = L"CloseLogFile"; nStatus = STAT_SESS_STOPPED_FAILED; break; } } hr = m_pDBGControl->Execute( DEBUG_OUTCTL_ALL_CLIENTS, szCmd, DEBUG_EXECUTE_DEFAULT ); // hr = m_pDBGControl->WaitForEvent(DEBUG_WAIT_DEFAULT, INFINITE); // hr = m_pDBGClient->EndSession(DEBUG_END_ACTIVE_TERMINATE); SetEvent( m_hEvent ); break; } if( strcmp( szCmd, "qd" ) == 0 ) { if( eDBGSessType == SessType_Automatic ) { hr = m_pDBGControl->CloseLogFile(); if( FAILED(hr) ) { bstrStatus = L"CloseLogFile"; nStatus = STAT_SESS_STOPPED_FAILED; break; } } hr = m_pDBGControl->Execute( DEBUG_OUTCTL_ALL_CLIENTS, szCmd, DEBUG_EXECUTE_DEFAULT ); /* hr = m_pDBGClient->DetachProcesses(); */ SetEvent( m_hEvent ); break; } hr = m_pDBGControl->Execute( DEBUG_OUTCTL_ALL_CLIENTS, szCmd, DEBUG_EXECUTE_DEFAULT ); if( FAILED(hr) ) { bstrStatus = L"DbgControl::Execute failed"; nStatus = STAT_SESS_STOPPED_FAILED; break; } Sleep(2000); hr = m_pDBGControl->GetExecutionStatus(&ExecStatus); if( FAILED(hr) ) { bstrStatus = L"GetExecutionStatus"; nStatus = STAT_SESS_STOPPED_FAILED; break; } } // Will have to terminate if either no deubuggee or // stop is requested.. while( CanContinue() == S_OK ); hr = m_pDBGControl->GetExecutionStatus(&ExecStatus); if( FAILED(hr) ) { bstrStatus = L"DbgControl::GetExecutionStatus failed"; nStatus = STAT_SESS_STOPPED_FAILED; break; } if(ExecStatus != DEBUG_STATUS_NO_DEBUGGEE) { if( eDBGSessType == SessType_Automatic ) { m_pDBGControl->CloseLogFile(); } m_pDBGClient->EndSession(DEBUG_END_PASSIVE); } } while(FALSE); if(FAILED(hr)) { #ifdef _DEBUG m_pASTManager->SetSessionStatus( m_pEmSessObj->guidstream, STAT_SESS_STOPPED_FAILED, hr, bstrStatus, true, true ); #else m_pASTManager->SetSessionStatus( m_pEmSessObj->guidstream, STAT_SESS_STOPPED_FAILED, hr, NULL, true, true ); #endif } // // When we are here, the debug session is guarenteed to be stopped. // { EmObject EmObj; EmObj.dateEnd = CServiceModule::GetCurrentTime(); m_pASTManager->UpdateSessObject( m_pEmSessObj->guidstream, EMOBJ_FLD_DATEEND, &EmObj ); } if( m_pEcxFile ) { fclose( m_pEcxFile ); m_pEcxFile = NULL; } StopServer(); return hr; } HRESULT CEMSessionThread::StartManualExcepMonitoring( char *pszConnectString ) { ATLTRACE(_T("CEMSessionThread::StartManualExcepMonitoring\n")); HRESULT hr = E_FAIL, hrActual = E_FAIL; char szLogFile[_MAX_PATH+1] = ""; TCHAR szLogDir[_MAX_PATH+1] = _T(""); char szEcxFile[_MAX_PATH+1] = ""; TCHAR szEcxDir[_MAX_PATH+1] = _T(""); bool bStop = FALSE; char szCmd[_MAX_PATH+1] = ""; DWORD dwBufSize = _MAX_PATH; EmSessionStatus nStatus = STAT_SESS_NONE_STAT_NONE; bstr_t bstrStatus; do { _ASSERTE(m_bstrEcxFilePath != NULL); _Module.GetEmDirectory( EMOBJ_CMDSET, szEcxDir, dwBufSize, NULL, NULL ); _stprintf(szEcxDir, _T("%s\\%s"), szEcxDir, m_bstrEcxFilePath); wcstombs( szEcxFile, szEcxDir, dwBufSize ); dwBufSize = _MAX_PATH; _Module.GetEmDirectory( EMOBJ_LOGFILE, szLogDir, dwBufSize, NULL, NULL ); _stprintf(szLogDir, _T("%s\\%s"), szLogDir, _T("EmLog.Dbl")); wcstombs( szLogFile, szLogDir, dwBufSize ); hr = DebugConnect( pszConnectString, IID_IDebugClient, (void **)&m_pDBGClient ); if( FAILED(hr) ) { hrActual = hr; hr = EMERROR_CONNECTIONTOSERVERFAILED; nStatus = STAT_SESS_STOPPED_FAILED; bstrStatus = L"DebugConnect failed"; break; } #ifdef _DEBUG m_pASTManager->SetSessionStatus( m_pEmSessObj->guidstream, STAT_SESS_DEBUG_IN_PROGRESS_NONE, hr, L"DebugConnect Succeeded.." ); #else m_pASTManager->SetSessionStatus( m_pEmSessObj->guidstream, STAT_SESS_DEBUG_IN_PROGRESS_NONE, hr, NULL ); #endif hr = m_pDBGClient->QueryInterface( IID_IDebugControl, (void **)&m_pDBGControl ); if( FAILED(hr) ) { nStatus = STAT_SESS_STOPPED_FAILED; bstrStatus = L"IDbgClient::QIFace ( IDbgControl ) failed"; break; } hr = m_pDBGControl->OpenLogFile(szLogFile, FALSE); if( FAILED(hr) ) { hrActual = hr; hr = EMERROR_UNABLETOCREATELOGFILE; nStatus = STAT_SESS_STOPPED_FAILED; bstrStatus = L"Open log file failed"; break; } hr = m_pDBGControl->ExecuteCommandFile( DEBUG_OUTCTL_LOG_ONLY, szEcxFile, DEBUG_EXECUTE_DEFAULT ); if( FAILED(hr) ) { hrActual = hr; hr = EMERROR_ECXFILEEXECUTIONFAILED; nStatus = STAT_SESS_STOPPED_FAILED; bstrStatus = L"ExecCommandFile failed"; break; } m_EventCallbacks.m_pEMThread = this; hr = m_pDBGClient->SetEventCallbacks(&m_EventCallbacks); if( FAILED(hr) ) { hrActual = hr; hr = EMERROR_CALLBACKSCANNOTBEREGISTERED; nStatus = STAT_SESS_STOPPED_FAILED; bstrStatus = L"SetEventCallback failed"; break; } ULONG ExecStatus = DEBUG_STATUS_BREAK; // m_pDBGClient->ConnectSession(DEBUG_CONNECT_SESSION_DEFAULT); while( true ) { hr = m_pDBGClient->DispatchCallbacks(INFINITE); // Milli Secs.. FAILEDHR_BREAK(hr); //DispatchCallbacks return S_FALSE if timeout expires } hr = S_OK; } while(FALSE); #ifdef _DEBUG m_pASTManager->SetSessionStatus( m_pEmSessObj->guidstream, STAT_SESS_STOPPED_SUCCESS, hr, bstrStatus ); #else m_pASTManager->SetSessionStatus( m_pEmSessObj->guidstream, STAT_SESS_STOPPED_SUCCESS, hr, NULL ); #endif return hr; } HRESULT CEMSessionThread::StartCDBServer ( IN LPTSTR lpszConnectString ) { ATLTRACE(_T("CEMSessionThread::StartCDBServer\n")); TCHAR szCdbDir[_MAX_PATH+1] = _T(""); ULONG ccCdbDir = _MAX_PATH; HRESULT hr = E_FAIL; ccCdbDir = _MAX_DIR; hr = _Module.GetCDBInstallDir( szCdbDir, &ccCdbDir ); if( FAILED(hr) ) return hr; _tcsncat( szCdbDir, _T("\\cdb.exe"), _MAX_DIR ); BOOL bCdbCreated = CreateProcess(// This has to be obtained from the registry... szCdbDir, lpszConnectString, NULL, NULL, FALSE, CREATE_NEW_PROCESS_GROUP | CREATE_NEW_CONSOLE, NULL, NULL, &m_sp, &m_pi ); if(bCdbCreated == FALSE){ return HRESULT_FROM_WIN32(GetLastError()); } // // Wait till CDB does some initializations.. // Don't know how long to wait.. have to figure out a way.. // Sleep(2000); return S_OK; } HRESULT CEMSessionThread::GetClientConnectString ( IN OUT LPTSTR pszConnectString, IN DWORD dwBuffSize ) { ATLTRACE(_T("CEMSessionThread::GetClientConnectString\n")); _ASSERTE(pszConnectString != NULL); _ASSERTE(dwBuffSize > 0L); HRESULT hr = E_FAIL; DWORD dwBuff = MAX_COMPUTERNAME_LENGTH; TCHAR szCompName[MAX_COMPUTERNAME_LENGTH + 1]; do { if( pszConnectString == NULL || dwBuffSize <= 0L ) break; if(GetComputerName(szCompName, &dwBuff) == FALSE){ HRESULT_FROM_WIN32(GetLastError()); break; } if( m_nPort != 0 ){ _stprintf(pszConnectString, _T("tcp:server=%s,port=%d"), szCompName, m_nPort); } else { _stprintf(pszConnectString, _T("npipe:server=%s,pipe=EM_%d"), szCompName, m_pEmSessObj->nId); } hr = S_OK; } while( false ); return hr; } HRESULT CEMSessionThread::GetServerConnectString ( IN OUT LPTSTR lpszConnectString, IN DWORD dwBuffSize ) { ATLTRACE(_T("CEMSessionThread::GetServerConnectString\n")); _ASSERTE(lpszConnectString != NULL); _ASSERTE(dwBuffSize > 0L); HRESULT hr = E_FAIL; do { if( lpszConnectString == NULL || dwBuffSize <= 0L ) break; if( m_nPort != 0 ){ _stprintf(lpszConnectString, _T(" -server tcp:port=%d -p %d"), m_nPort, m_pEmSessObj->nId); } else { _stprintf(lpszConnectString, _T(" -server npipe:pipe=EM_%d -p %d"), m_pEmSessObj->nId, m_pEmSessObj->nId); } hr = S_OK; } while( false ); return hr; } typedef BOOL (WINAPI*PFNWR)( IN HANDLE hProcess, IN DWORD ProcessId, IN HANDLE hFile, IN MINIDUMP_TYPE DumpType, IN CONST PMINIDUMP_EXCEPTION_INFORMATION ExceptionParam, OPTIONAL IN CONST PMINIDUMP_USER_STREAM_INFORMATION UserStreamParam, OPTIONAL IN CONST PMINIDUMP_CALLBACK_INFORMATION CallbackParam OPTIONAL ); HRESULT CEMSessionThread::CreateDumpFile( BOOL bMiniDump ) { ATLTRACE(_T("CEMSessionThread::CreateDumpFile\n")); HRESULT hr = E_FAIL; HANDLE hDumpFile = INVALID_HANDLE_VALUE, hProcess = NULL; HMODULE hDbgHelp = NULL; LONG lStatus = 0L; TCHAR szDumpFile[_MAX_PATH + 1] = _T(""); // a-kjaw, bug ID: 296024/25 DWORD dwBufSize = _MAX_PATH; TCHAR szCmd[_MAX_PATH + 1] = _T(""); // a-kjaw, bug ID: 296026 DWORD dwLastErr = 0L; TCHAR szFileExt[_MAX_EXT + 1] = _T(""); LPCTSTR lpszDbgHelpDll = _T("\\dbghelp.dll"), lpszUserDumpExe = _T("\\userdump.exe"); do { hr = m_pASTManager->GetSessionStatus( m_pEmSessObj->guidstream, &lStatus ); FAILEDHR_BREAK(hr); // // We cannot generate dump files if the debuggee has stopped.. // if( lStatus & STAT_SESS_STOPPED ) { hr = EMERROR_INVALIDPROCESS; break; } if( bMiniDump ){ _Module.GetEmDirectory( EMOBJ_MINIDUMP, szCmd, dwBufSize, szFileExt, _MAX_EXT ); CreateDirectory( szCmd, NULL ); GetUniqueFileName ( m_pEmSessObj, szDumpFile, _T("mini"), szFileExt, false ); _tcscat( szCmd, _T("\\")); _tcscat( szCmd, szDumpFile); hDumpFile = CreateFile( szCmd, GENERIC_ALL, 0, NULL, // sa CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL ); if( hDumpFile == INVALID_HANDLE_VALUE ) { dwLastErr = GetLastError(); hr = HRESULT_FROM_WIN32(dwLastErr); break; } dwBufSize = _MAX_DIR; hr = _Module.GetEmInstallDir( szCmd, &dwBufSize ); if( FAILED(hr) ) break; _tcsncat( szCmd, lpszDbgHelpDll, _MAX_PATH ); hDbgHelp = LoadLibrary(szCmd); if( hDbgHelp == NULL ) { hr = HRESULT_FROM_WIN32(GetLastError()); break; } PFNWR pFunc = (PFNWR) GetProcAddress(hDbgHelp, "MiniDumpWriteDump"); if(!pFunc) { hr = E_FAIL; break; } hr = HRESULT_FROM_WIN32(GetProcessHandle(m_pEmSessObj->nId, &hProcess)); FAILEDHR_BREAK(hr); hr = S_FALSE; if( pFunc(hProcess, m_pEmSessObj->nId, (HANDLE)hDumpFile, MiniDumpNormal, NULL, NULL, NULL) ) { hr = S_OK; } } else{ dwBufSize = _MAX_PATH; _Module.GetEmDirectory( EMOBJ_USERDUMP, szDumpFile, dwBufSize, szFileExt, _MAX_EXT ); CreateDirectory( szDumpFile, NULL ); _stprintf( szCmd, _T(" %d \"%s\""), m_pEmSessObj->nId, szDumpFile ); GetUniqueFileName ( m_pEmSessObj, szDumpFile, _T("user"), szFileExt, false ); _tcscat(szCmd, _T("\\")); _tcscat(szCmd, szDumpFile); STARTUPINFO sp; PROCESS_INFORMATION pi; ZeroMemory(&sp, sizeof(sp)); ZeroMemory(&pi, sizeof(pi)); dwBufSize = _MAX_DIR; hr = _Module.GetEmInstallDir( szDumpFile, &dwBufSize ); if( FAILED(hr) ) break; _tcsncat( szDumpFile, lpszUserDumpExe, _MAX_PATH ); BOOL bRet = CreateProcess(// This has to be obtained from the registry... szDumpFile, szCmd, NULL, NULL, FALSE, CREATE_NO_WINDOW, NULL, NULL, &sp, &pi ); WaitForSingleObject( pi.hProcess, INFINITE ); CloseHandle(pi.hProcess); hr = S_OK; } } while(FALSE); if(hDumpFile != INVALID_HANDLE_VALUE) { CloseHandle(hDumpFile); } if(hDbgHelp) { FreeLibrary( hDbgHelp ); } if(hProcess) { CloseHandle( hProcess ); } if(hr == S_OK){ lStatus |= STAT_FILECREATED_SUCCESSFULLY; } else { lStatus |= STAT_FILECREATION_FAILED; } hr = m_pASTManager->SetSessionStatus( m_pEmSessObj->guidstream, lStatus, hr, NULL ); return hr; } HRESULT CEMSessionThread::StopDebugging( ) { ATLTRACE(_T("CEMSessionThread::StopDebugging\n")); HRESULT hr = S_OK; IDebugClient *pDBGClntLocal = NULL; IDebugControl *pDBGCtrlLocal = NULL; do { /* // We seem to allow manual sessions to be stopped too.. if( eDBGSessType == SessType_Manual ) { hr = S_OK; break; } */ m_bContinueSession = FALSE; eDBGServie = DBGService_Stop; hr = m_pDBGClient->CreateClient(&pDBGClntLocal); FAILEDHR_BREAK(hr); hr = pDBGClntLocal->ExitDispatch(m_pDBGClient); FAILEDHR_BREAK(hr); WaitForSingleObject( m_hEvent, INFINITE ); #ifdef _DEBUG hr = m_pASTManager->SetSessionStatus( m_pEmSessObj->guidstream, STAT_SESS_STOPPED_SUCCESS, S_OK, L"CEMSessionThread::StopDebugging - called" ); #else hr = m_pASTManager->SetSessionStatus( m_pEmSessObj->guidstream, STAT_SESS_STOPPED_SUCCESS, S_OK, NULL ); #endif FAILEDHR_BREAK(hr); } while(FALSE); return hr; } HRESULT CEMSessionThread::GetCmd ( IN eDBGServiceRequested eDBGSvc, IN OUT char * pszCmdBuff, IN OUT DWORD &dwBufLen ) { ATLTRACE(_T("CEMSessionThread::GetCmd\n")); HRESULT hr = S_OK; char szPostDebug[_MAX_PATH] = "C:\\Program Files\\Debuggers\\bin\\em\\config\\PostDebug.ecx"; _ASSERTE( pszCmdBuff != NULL ); _ASSERTE( dwBufLen > 0 ); do { if( pszCmdBuff == NULL || dwBufLen < 1L ){ hr = E_INVALIDARG; break; } strcpy( pszCmdBuff, "" ); switch( eDBGSvc ) { case DBGService_Stop: case DBGService_HandleException: strncpy( pszCmdBuff, "q", dwBufLen ); break; case DBGService_Cancel: strncpy( pszCmdBuff, "qd", dwBufLen ); // QD (Quit and Detach); break; case DBGService_CreateMiniDump: sprintf( pszCmdBuff, ".dump /m d:\\EMMiniDump%d.dmp", m_pEmSessObj->nId ); break; case DBGService_CreateUserDump: sprintf( pszCmdBuff, ".dump d:\\EMUserDump%d.dmp", m_pEmSessObj->nId ); break; case DBGService_Go: strncpy( pszCmdBuff, "g", dwBufLen ); break; default: hr = E_INVALIDARG; } } while( false ); dwBufLen = strlen( pszCmdBuff ); return hr; } HRESULT CEMSessionThread::OnException ( IN PEXCEPTION_RECORD64 pException ) { ATLTRACE(_T("CEMSessionThread::OnException\n")); HRESULT hr = S_OK; IDebugClient *pDBGClntLocal = NULL; DWORD excpcd = pException->ExceptionCode; TCHAR szTemp[_MAX_PATH+1] = _T(""); TCHAR szDesc[sizeof EmObject+1] = _T(""); do { if(excpcd == EXCEPTION_BREAKPOINT){ break; } if(m_bGenerateMiniDump) { hr = CreateDumpFile( TRUE ); FAILEDHR_BREAK(hr); } if(m_bGenerateUserDump) { hr = CreateDumpFile( FALSE ); FAILEDHR_BREAK(hr); } if(excpcd == EXCEPTION_ACCESS_VIOLATION){ #ifdef _DEBUG m_pASTManager->SetSessionStatus(m_pEmSessObj->guidstream, STAT_SESS_STOPPED_ACCESSVIOLATION_OCCURED, S_OK, L"OnException - AV"); #else m_pASTManager->SetSessionStatus(m_pEmSessObj->guidstream, STAT_SESS_STOPPED_ACCESSVIOLATION_OCCURED, S_OK, NULL); #endif ::LoadString(_Module.GetResourceInstance(), IDS_DEBUGGEE_ACCESSVIOLATION, szTemp, _MAX_PATH); GetDescriptionFromEmObj(m_pEmSessObj, szDesc, sizeof EmObject, szTemp); NotifyAdmin(szDesc); } else{ // Exception.. #ifdef _DEBUG m_pASTManager->SetSessionStatus(m_pEmSessObj->guidstream, STAT_SESS_STOPPED_EXCEPTION_OCCURED, S_OK, L"OnException - Exception"); #else m_pASTManager->SetSessionStatus(m_pEmSessObj->guidstream, STAT_SESS_STOPPED_EXCEPTION_OCCURED, S_OK, NULL); #endif ::LoadString(_Module.GetResourceInstance(), IDS_DEBUGGEE_EXCEPTION, szTemp, _MAX_PATH); GetDescriptionFromEmObj(m_pEmSessObj, szDesc, sizeof EmObject, szTemp); NotifyAdmin(szDesc); } hr = m_pDBGClient->CreateClient(&pDBGClntLocal); FAILEDHR_BREAK(hr); hr = pDBGClntLocal->ExitDispatch(m_pDBGClient); FAILEDHR_BREAK(hr); } while(FALSE); return hr; } HRESULT CEMSessionThread::CanContinue() { ATLTRACE(_T("CEMSessionThread::CanContinue\n")); ULONG ExecStatus = DEBUG_STATUS_BREAK; HRESULT hr = S_OK; do { hr = m_pDBGControl->GetExecutionStatus(&ExecStatus); FAILEDHR_BREAK(hr); // // We don't have anything to do if the debuggee // has exited. // if( ExecStatus == DEBUG_STATUS_NO_DEBUGGEE ){ hr = S_FALSE; break; } if( IsStopRequested() == TRUE ){ hr = S_FALSE; break; } } while( false ); return hr; } HRESULT CEMSessionThread::KeepDebuggeeRunning() { ATLTRACE(_T("CEMSessionThread::KeepDebuggeeRunning\n")); HRESULT hr = E_FAIL; ULONG ExecStatus = DEBUG_STATUS_BREAK; do { hr = m_pDBGControl->GetExecutionStatus(&ExecStatus); FAILEDHR_BREAK(hr); if( ExecStatus != DEBUG_STATUS_BREAK ){ break; } hr = BreakIn(); FAILEDHR_BREAK(hr); hr = m_pDBGControl->Execute( DEBUG_OUTCTL_ALL_CLIENTS, "g", DEBUG_EXECUTE_DEFAULT ); FAILEDHR_BREAK(hr); } while( false ); return hr; } HRESULT CEMSessionThread::BreakIn() { ATLTRACE(_T("CEMSessionThread::BreakIn\n")); HRESULT hr = E_FAIL; ULONG ExecStatus = DEBUG_STATUS_BREAK; do { hr = m_pDBGControl->GetExecutionStatus(&ExecStatus); FAILEDHR_BREAK(hr); if( ExecStatus == DEBUG_STATUS_GO || ExecStatus == DEBUG_STATUS_GO_HANDLED || ExecStatus == DEBUG_STATUS_GO_NOT_HANDLED ){ hr = m_pDBGControl->SetInterrupt(DEBUG_INTERRUPT_ACTIVE); FAILEDHR_BREAK(hr); // // Though SetInterrupt returns immediately, it takes some time // for the interrrupt to occur.. // Sleep(2000); } } while( false ); return hr; } HRESULT CEMSessionThread::OnProcessExit ( IN ULONG nExitCode ) { ATLTRACE(_T("CEMSessionThread::OnProcessExit\n")); HRESULT hr = S_OK; IDebugClient *pDBGClntLocal = NULL; IDebugControl *pDBGCtrlLocal = NULL; do { #ifdef _DEBUG hr = m_pASTManager->SetSessionStatus(m_pEmSessObj->guidstream, STAT_SESS_STOPPED_DEBUGGEE_EXITED, S_OK, L"OnProcessExit"); #else hr = m_pASTManager->SetSessionStatus(m_pEmSessObj->guidstream, STAT_SESS_STOPPED_DEBUGGEE_EXITED, S_OK, NULL); #endif FAILEDHR_BREAK(hr); hr = m_pDBGClient->CreateClient(&pDBGClntLocal); FAILEDHR_BREAK(hr); hr = pDBGClntLocal->ExitDispatch(m_pDBGClient); FAILEDHR_BREAK(hr); } while ( false ); return hr; } HRESULT CEMSessionThread::Execute() { ATLTRACE(_T("CEMSessionThread::Execute\n")); HRESULT hr = E_FAIL; do { hr = m_pDBGControl->Execute( DEBUG_OUTCTL_ALL_CLIENTS, "? a;g", DEBUG_EXECUTE_DEFAULT ); FAILEDHR_BREAK(hr); } while ( false ); return hr; } HRESULT CEMSessionThread::InitAutomaticSession ( IN BOOL bRecursive, IN BSTR bstrEcxFilePath, IN BSTR bstrNotificationString, IN BSTR bstrAltSymPath, IN BOOL bGenerateMiniDump, IN BOOL bGenerateUserDump ) { ATLTRACE(_T("CEMSessionThread::InitAutomaticSession\n")); _ASSERTE(bstrEcxFilePath != NULL); if(bstrEcxFilePath == NULL) { return E_INVALIDARG; } eDBGSessType = SessType_Automatic; m_bRecursive = bRecursive; m_bstrEcxFilePath = ::SysAllocString(bstrEcxFilePath); m_bstrNotificationString = ::SysAllocString(bstrNotificationString); m_bstrAltSymPath = ::SysAllocString(bstrAltSymPath); m_bGenerateMiniDump = bGenerateMiniDump; m_bGenerateUserDump = bGenerateUserDump; return S_OK; } HRESULT CEMSessionThread::InitManualSession ( IN BSTR bstrEcxFilePath, IN UINT nPortNumber, IN BSTR bstrUserName, IN BSTR bstrPassword, IN BOOL bBlockIncomingIPConnections, IN BSTR bstrAltSymPath ) { ATLTRACE(_T("CEMSessionThread::InitManualSession\n")); _ASSERTE( nPortNumber != 0 ); _ASSERTE( bstrUserName != NULL ); _ASSERTE( bstrPassword != NULL ); HRESULT hr = E_FAIL; do { if( ( nPortNumber == 0 ) || ( bstrUserName == NULL )|| ( bstrPassword == NULL ) ) { hr = E_INVALIDARG; break; } eDBGSessType = SessType_Manual; if(bstrEcxFilePath) m_bstrEcxFilePath = ::SysAllocString(bstrEcxFilePath); m_nPort = nPortNumber; m_bBlockIncomingIPConnections = bBlockIncomingIPConnections; if(bstrUserName) m_bstrUserName = ::SysAllocString(bstrUserName); if(bstrPassword) m_bstrPassword = ::SysAllocString(bstrPassword); if(bstrAltSymPath) m_bstrAltSymPath = ::SysAllocString(bstrAltSymPath); hr = S_OK; } while ( false ); return hr; } HRESULT CEMSessionThread::StopServer() { ATLTRACE(_T("CEMSessionThread::StopServer\n")); HRESULT hr = E_FAIL; do { if(m_pi.hProcess){ TerminateProcess(m_pi.hProcess, 0); ZeroMemory((void *)&m_pi, sizeof PROCESS_INFORMATION); } } while( false ); return hr; } HRESULT CEMSessionThread::NotifyAdmin(LPCTSTR lpszData) { ATLTRACE(_T("CEMSessionThread::NotifyAdmin\n")); DWORD dwLastRet = 0L; CNotify AdminNotify(m_bstrNotificationString, lpszData); dwLastRet = AdminNotify.Notify(); return HRESULT_FROM_WIN32(dwLastRet); } HRESULT CEMSessionThread::GetDescriptionFromEmObj ( const PEmObject pEmObj, LPTSTR lpszDesc, ULONG cchDesc, LPCTSTR lpszHeader /* = NULL */ ) const { _ASSERTE( pEmObj != NULL ); _ASSERTE( lpszDesc != NULL ); _ASSERTE( cchDesc > 0 ); HRESULT hr = E_FAIL; TCHAR szTemp[_MAX_PATH+1] = _T(""); int j = 0; do { if( pEmObj == NULL || lpszDesc == NULL || cchDesc <= 0 ) { return E_INVALIDARG; } /* short type; unsigned char guidstream[ 16 ]; LONG nId; TCHAR szName[ 256 ]; TCHAR szSecName[ 256 ]; LONG nStatus; DATE dateStart; DATE dateEnd; TCHAR szBucket1[ 64 ]; DWORD dwBucket1; HRESULT hr; */ j = _sntprintf(lpszDesc, cchDesc, _T("%s"), _T("")); if( lpszHeader ) { j += _sntprintf(lpszDesc+j, cchDesc, _T("%s -- "), lpszHeader); } if( pEmObj->type == EMOBJ_PROCESS ) { ::LoadString(_Module.GetResourceInstance(), IDS_PROCESS, szTemp, _MAX_PATH); } else if( pEmObj->type == EMOBJ_SERVICE ) { ::LoadString(_Module.GetResourceInstance(), IDS_SERVICE, szTemp, _MAX_PATH); } if(_tcscmp(szTemp, _T("")) != 0) { j += _sntprintf(lpszDesc+j, cchDesc, _T("%s : %d - "), szTemp, pEmObj->nId); } if(_tcscmp(pEmObj->szName, _T("")) != 0) { ::LoadString(_Module.GetResourceInstance(), IDS_IMAGENAME, szTemp, _MAX_PATH); j += _sntprintf(lpszDesc+j, cchDesc, _T("%s : %s - "), szTemp, pEmObj->szName); } if(_tcscmp(pEmObj->szSecName, _T("")) != 0) { ::LoadString(_Module.GetResourceInstance(), IDS_SHORTNAME, szTemp, _MAX_PATH); j += _sntprintf(lpszDesc+j, cchDesc, _T("%s : %s - "), szTemp, pEmObj->szSecName); } #ifdef _DEBUG StringFromGUID2(*(GUID*)pEmObj->guidstream, szTemp, _MAX_PATH); if( pEmObj->guidstream && strcmp((const char*)pEmObj->guidstream, "") != 0 ) { j += _sntprintf(lpszDesc+j, cchDesc, _T("%s"), szTemp); } #endif // _DEBUG } while ( false ); return hr; } HRESULT CEMSessionThread::CancelDebugging() { ATLTRACE(_T("CEMSessionThread::CancelDebugging\n")); HRESULT hr = S_OK; IDebugClient *pDBGClntLocal = NULL; IDebugControl *pDBGCtrlLocal = NULL; do { if( eDBGSessType == SessType_Manual ) { hr = S_OK; break; } m_bContinueSession = FALSE; eDBGServie = DBGService_Cancel; hr = m_pDBGClient->CreateClient(&pDBGClntLocal); FAILEDHR_BREAK(hr); hr = pDBGClntLocal->ExitDispatch(m_pDBGClient); FAILEDHR_BREAK(hr); WaitForSingleObject( m_hEvent, INFINITE ); #ifdef _DEBUG hr = m_pASTManager->SetSessionStatus( m_pEmSessObj->guidstream, STAT_SESS_STOPPED_SUCCESS, S_OK, L"CEMSessionThread::CancelDebugging - called" ); #else hr = m_pASTManager->SetSessionStatus( m_pEmSessObj->guidstream, STAT_SESS_STOPPED_SUCCESS, S_OK, NULL ); #endif FAILEDHR_BREAK(hr); } while(FALSE); return hr; } HRESULT CEMSessionThread::ExecuteCommandsTillGo ( OUT DWORD *pdwRes ) { _ASSERTE( m_pEcxFile != NULL ); _ASSERTE( m_pDBGControl != NULL ); HRESULT hr = E_FAIL; char cmd[MAX_COMMAND] = ""; ULONG ExecStatus = DEBUG_STATUS_BREAK; __try { if( m_pEcxFile == NULL || m_pDBGControl == NULL ) { hr = E_INVALIDARG; goto qExecuteCommandsTillGo; } if( pdwRes ) *pdwRes = 0L; // success Sleep(2000); // do { hr = m_pDBGControl->GetExecutionStatus(&ExecStatus); if( FAILED(hr) ) { goto qExecuteCommandsTillGo; } // // we can execute commands only when the debuggee is in // this state.. // if( ExecStatus != DEBUG_STATUS_BREAK ) { hr = E_FAIL; goto qExecuteCommandsTillGo; } if (fgets(cmd, MAX_COMMAND-1, m_pEcxFile)) { cmd[strlen(cmd) - 1] = 0; if( strcmp( cmd, "g" ) == 0 || strcmp( cmd, "G" ) == 0 ) { hr = S_OK; goto qExecuteCommandsTillGo; } hr = m_pDBGControl->OutputPrompt(DEBUG_OUTPUT_PROMPT, "> "); if( FAILED(hr) ) { goto qExecuteCommandsTillGo; } hr = m_pDBGControl->Execute( DEBUG_OUTCTL_ALL_CLIENTS, cmd, DEBUG_EXECUTE_ECHO ); if( FAILED(hr) ) { goto qExecuteCommandsTillGo; } } else // eof reached..?? { if( pdwRes ) { *pdwRes = GetLastError(); } GetLastError(); hr = S_FALSE; goto qExecuteCommandsTillGo; } } while ( true ); qExecuteCommandsTillGo: if( FAILED(hr) ) {} } __except ( EXCEPTION_EXECUTE_HANDLER, 1 ) { hr = E_UNEXPECTED; _ASSERTE( false ); } return hr; }