568 lines
13 KiB
C++
568 lines
13 KiB
C++
// EmDebugSession.cpp : Implementation of CEmDebugSession
|
|
#include "stdafx.h"
|
|
#include "Emsvc.h"
|
|
#include "EmDebugSession.h"
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
// CEmDebugSession
|
|
|
|
|
|
STDMETHODIMP CEmDebugSession::InterfaceSupportsErrorInfo(REFIID riid)
|
|
{
|
|
static const IID* arr[] =
|
|
{
|
|
&IID_IEmDebugSession
|
|
};
|
|
for (int i=0; i < sizeof(arr) / sizeof(arr[0]); i++)
|
|
{
|
|
if (::InlineIsEqualGUID(*arr[i],riid))
|
|
return S_OK;
|
|
}
|
|
return S_FALSE;
|
|
}
|
|
|
|
STDMETHODIMP
|
|
CEmDebugSession::DebugEx
|
|
(
|
|
IN BSTR bstrEmObj,
|
|
IN SessionType eSessType,
|
|
IN BSTR bstrEcxFilePath,
|
|
IN LONG lParam,
|
|
IN OPT VARIANT vtUserName,
|
|
IN OPT VARIANT vtPassword,
|
|
IN OPT VARIANT vtPort,
|
|
IN OPT VARIANT vtNotifyAdmin,
|
|
IN OPT VARIANT vtAltSymPath
|
|
)
|
|
{
|
|
ATLTRACE(_T("CEmDebugSession::DebugEx\n"));
|
|
|
|
_ASSERTE(bstrEmObj != NULL);
|
|
|
|
HRESULT hr = E_FAIL;
|
|
PEmObject pEmObj = NULL;
|
|
PEMSession pEmSess = NULL;
|
|
|
|
BSTR bstrUserName = GetBSTR(vtUserName);
|
|
BSTR bstrPassword = GetBSTR(vtPassword);
|
|
BSTR bstrNotificationString = GetBSTR(vtNotifyAdmin);
|
|
BSTR bstrAltSymPath = GetBSTR(vtAltSymPath);
|
|
UINT nPort = GetInteger(vtPort);
|
|
EmObject EmObj;
|
|
|
|
m_pcs->ReadLock();
|
|
|
|
__try {
|
|
|
|
do
|
|
{
|
|
if( (bstrEmObj == NULL) ||
|
|
(vtUserName.vt != VT_EMPTY && IsBSTR(vtUserName) == FALSE) ||
|
|
(vtPassword.vt != VT_EMPTY && IsBSTR(vtPassword) == FALSE) ||
|
|
(vtPort.vt != VT_EMPTY && IsInteger(vtPort) == FALSE) ||
|
|
(vtNotifyAdmin.vt != VT_EMPTY && IsBSTR(vtNotifyAdmin) == FALSE) ||
|
|
(vtAltSymPath.vt != VT_EMPTY && IsBSTR(vtAltSymPath) == FALSE)
|
|
)
|
|
{
|
|
|
|
hr = E_INVALIDARG;
|
|
break;
|
|
}
|
|
|
|
pEmObj = GetEmObj(bstrEmObj);
|
|
_ASSERTE( pEmObj != NULL );
|
|
|
|
//
|
|
// If it is being debugged already this call should not
|
|
// have been made..
|
|
//
|
|
|
|
// hr = m_pASTManager->IsAlreadyBeingDebugged(pEmObj);
|
|
LONG lStatus = 0L;
|
|
hr = m_pASTManager->GetSessionStatus( m_pEmObj->guidstream, &lStatus );
|
|
FAILEDHR_BREAK(hr);
|
|
|
|
// if( hr == S_OK ) {
|
|
if( HIWORD(lStatus) > HIWORD(STAT_SESS_NOT_STARTED) ) {
|
|
|
|
hr = EMERROR_PROCESSBEINGDEBUGGED;
|
|
break;
|
|
}
|
|
|
|
ZeroMemory((void *)&EmObj, sizeof EmObj);
|
|
|
|
if( eSessType == SessType_Automatic ) {
|
|
|
|
hr = StartAutomaticSession(
|
|
(lParam & RECURSIVE_MODE),
|
|
bstrEcxFilePath,
|
|
bstrNotificationString,
|
|
bstrAltSymPath,
|
|
(lParam & PRODUCE_MINI_DUMP),
|
|
(lParam & PRODUCE_USER_DUMP)
|
|
);
|
|
|
|
EmObj.type2 = SessType_Automatic;
|
|
EmObj.dateStart = CServiceModule::GetCurrentTime();
|
|
|
|
m_pASTManager->UpdateSessObject( m_pEmObj->guidstream,
|
|
EMOBJ_FLD_TYPE2 | EMOBJ_FLD_DATESTART,
|
|
&EmObj
|
|
);
|
|
}
|
|
|
|
else {
|
|
|
|
hr = StartManualSession(
|
|
bstrEcxFilePath,
|
|
nPort,
|
|
bstrUserName,
|
|
bstrPassword,
|
|
(lParam && BLOCK_INCOMING_IPCALLS),
|
|
bstrAltSymPath
|
|
);
|
|
FAILEDHR_BREAK(hr);
|
|
|
|
EmObj.type2 = SessType_Manual;
|
|
EmObj.dateStart = CServiceModule::GetCurrentTime();
|
|
|
|
m_pASTManager->UpdateSessObject( m_pEmObj->guidstream,
|
|
EMOBJ_FLD_TYPE2 | EMOBJ_FLD_DATESTART,
|
|
&EmObj
|
|
);
|
|
}
|
|
|
|
}
|
|
while( false );
|
|
|
|
if(SUCCEEDED(hr)) {
|
|
|
|
m_pASTManager->SetSessionStatus(
|
|
pEmObj->guidstream,
|
|
STAT_SESS_DEBUG_IN_PROGRESS_NONE,
|
|
hr,
|
|
NULL
|
|
);
|
|
|
|
SetMyselfAsMaster();
|
|
|
|
m_pASTManager->GetSession(pEmObj->guidstream, &pEmSess);
|
|
::SysFreeString(bstrEmObj);
|
|
bstrEmObj = CopyBSTR((LPBYTE)pEmSess->pEmObj, sizeof EmObject);
|
|
|
|
}
|
|
}
|
|
__except ( EXCEPTION_EXECUTE_HANDLER, 1 ) {
|
|
|
|
hr = E_UNEXPECTED;
|
|
_ASSERTE( false );
|
|
}
|
|
|
|
m_pcs->ReadUnlock();
|
|
|
|
return hr;
|
|
}
|
|
|
|
STDMETHODIMP CEmDebugSession::StopDebug(BOOL bForceStop)
|
|
{
|
|
ATLTRACE(_T("CEmDebugSession::StopDebug\n"));
|
|
|
|
HRESULT hr = E_FAIL;
|
|
LONG lStatus = 0L;
|
|
|
|
m_pcs->ReadLock();
|
|
|
|
__try {
|
|
|
|
hr = m_pASTManager->GetSessionStatus( m_pEmObj->guidstream, &lStatus );
|
|
if( FAILED(hr) ) { return hr; }
|
|
|
|
if( !(lStatus & STAT_SESS_DEBUG_IN_PROGRESS ) ) {
|
|
|
|
return (hr = EMERROR_PROCESSNOTBEINGDEBUGGED);
|
|
}
|
|
|
|
hr = CanTakeOwnership();
|
|
|
|
if( bForceStop && hr == EMERROR_SESSIONORPHANED ) {
|
|
|
|
hr = m_pASTManager->AdoptThisSession( m_pEmObj->guidstream );
|
|
if( SUCCEEDED(hr) ) {
|
|
|
|
SetMyselfAsMaster();
|
|
hr = S_OK;
|
|
}
|
|
}
|
|
|
|
if( hr == S_OK ) { hr = m_pEmSessThrd->StopDebugging(); }
|
|
}
|
|
__except ( EXCEPTION_EXECUTE_HANDLER, 1 ) {
|
|
|
|
hr = E_UNEXPECTED;
|
|
_ASSERTE( false );
|
|
}
|
|
|
|
m_pcs->ReadUnlock();
|
|
|
|
return hr;
|
|
}
|
|
|
|
STDMETHODIMP
|
|
CEmDebugSession::GenerateDumpFile
|
|
(
|
|
IN UINT nDumpType
|
|
)
|
|
{
|
|
ATLTRACE(_T("CEmDebugSession::GenerateDumpFile\n"));
|
|
|
|
HRESULT hr = E_FAIL,
|
|
hrStat = E_FAIL;
|
|
LONG lStatus = 0L;
|
|
|
|
m_pcs->ReadLock();
|
|
|
|
__try {
|
|
|
|
// we don't need this check any more, coz we allow anybody and everybody
|
|
// to generate dump files.. :(
|
|
// if( AmITheMaster() == FALSE ) { return EMERROR_NOTOWNER; }
|
|
|
|
hr = m_pEmSessThrd->CreateDumpFile( nDumpType );
|
|
|
|
}
|
|
__except ( EXCEPTION_EXECUTE_HANDLER, 1 ) {
|
|
|
|
hr = E_UNEXPECTED;
|
|
_ASSERTE( false );
|
|
}
|
|
|
|
m_pcs->ReadUnlock();
|
|
|
|
return hr;
|
|
}
|
|
|
|
STDMETHODIMP
|
|
CEmDebugSession::GetStatus
|
|
(
|
|
IN OUT BSTR bstrEmObj
|
|
)
|
|
{
|
|
ATLTRACE(_T("CEmDebugSession::GetStatus\n"));
|
|
|
|
_ASSERTE(bstrEmObj != NULL);
|
|
|
|
HRESULT hr = E_FAIL;
|
|
PEMSession pEmSess = NULL;
|
|
PEmObject pEmObj = NULL;
|
|
|
|
m_pcs->ReadLock();
|
|
|
|
__try {
|
|
|
|
do
|
|
{
|
|
if( bstrEmObj == NULL ){
|
|
|
|
hr = E_INVALIDARG;
|
|
break;
|
|
}
|
|
|
|
/*
|
|
// everyone should be able to call Refresh..
|
|
|
|
if( AmITheMaster() == FALSE ) {
|
|
|
|
hr = EMERROR_NOTOWNER;
|
|
break;
|
|
}
|
|
*/
|
|
|
|
pEmObj = GetEmObj(bstrEmObj);
|
|
|
|
// This should never happen
|
|
hr = EMERROR_INVALIDPROCESS;
|
|
if(m_pASTManager->GetSession(pEmObj->guidstream, &pEmSess) == S_OK){
|
|
|
|
::SysFreeString(bstrEmObj);
|
|
bstrEmObj = CopyBSTR((LPBYTE)pEmSess->pEmObj, sizeof EmObject);
|
|
hr = S_OK;
|
|
}
|
|
|
|
}
|
|
while( false );
|
|
}
|
|
__except ( EXCEPTION_EXECUTE_HANDLER, 1 ) {
|
|
|
|
hr = E_UNEXPECTED;
|
|
_ASSERTE( false );
|
|
}
|
|
|
|
m_pcs->ReadUnlock();
|
|
|
|
return hr;
|
|
}
|
|
|
|
bool CEmDebugSession::AmITheMaster()
|
|
{
|
|
ATLTRACE(_T("CEmDebugSession::AmITheMaster\n"));
|
|
|
|
return (m_bMaster);
|
|
}
|
|
|
|
HRESULT
|
|
CEmDebugSession::StartAutomaticSession
|
|
(
|
|
IN BOOL bRecursive,
|
|
IN BSTR bstrEcxFilePath,
|
|
IN BSTR bstrNotificationString,
|
|
IN BSTR bstrAltSymPath,
|
|
IN BOOL bGenMiniDumpFile,
|
|
IN BOOL bGenUserDumpFile
|
|
)
|
|
{
|
|
ATLTRACE(_T("CEmDebugSession::StartAutomaticSession\n"));
|
|
|
|
_ASSERTE(bstrEcxFilePath != NULL);
|
|
|
|
HRESULT hr = E_FAIL;
|
|
|
|
m_pcs->ReadLock();
|
|
|
|
__try {
|
|
|
|
do
|
|
{
|
|
if( bstrEcxFilePath == NULL ) {
|
|
|
|
hr = E_INVALIDARG;
|
|
break;
|
|
}
|
|
|
|
hr = m_pEmSessThrd->InitAutomaticSession(
|
|
bRecursive,
|
|
bstrEcxFilePath,
|
|
bstrNotificationString,
|
|
bstrAltSymPath,
|
|
bGenMiniDumpFile,
|
|
bGenUserDumpFile
|
|
);
|
|
FAILEDHR_BREAK(hr);
|
|
|
|
hr = HRESULT_FROM_WIN32(m_pEmSessThrd->Start());
|
|
FAILEDHR_BREAK(hr);
|
|
|
|
WaitForSingleObject( m_pEmSessThrd->m_hCDBStarted, INFINITE );
|
|
|
|
}
|
|
while( false );
|
|
}
|
|
__except ( EXCEPTION_EXECUTE_HANDLER, 1 ) {
|
|
|
|
hr = E_UNEXPECTED;
|
|
_ASSERTE( false );
|
|
}
|
|
|
|
m_pcs->ReadUnlock();
|
|
|
|
return hr;
|
|
}
|
|
|
|
HRESULT
|
|
CEmDebugSession::StartManualSession
|
|
(
|
|
IN BSTR bstrEcxFilePath,
|
|
IN UINT nPort,
|
|
IN BSTR bstrUserName,
|
|
IN BSTR bstrPassword,
|
|
IN BOOL bBlockIncomingIPConnections,
|
|
IN BSTR bstrAltSymPath
|
|
)
|
|
{
|
|
ATLTRACE(_T("CEmDebugSession::StartManualSession\n"));
|
|
|
|
_ASSERTE( nPort != NULL );
|
|
_ASSERTE( bstrUserName != NULL );
|
|
_ASSERTE( bstrPassword != NULL );
|
|
|
|
HRESULT hr = E_FAIL;
|
|
|
|
m_pcs->ReadLock();
|
|
|
|
__try {
|
|
|
|
do
|
|
{
|
|
|
|
if( ( nPort == NULL ) ||
|
|
( bstrUserName == NULL )||
|
|
( bstrPassword == NULL ) ) {
|
|
|
|
hr = E_INVALIDARG;
|
|
break;
|
|
}
|
|
|
|
if( m_pASTManager->IsPortInUse(nPort) == TRUE ) {
|
|
|
|
hr = EMERROR_PORTINUSE;
|
|
break;
|
|
}
|
|
|
|
hr = m_pEmSessThrd->InitManualSession(
|
|
bstrEcxFilePath,
|
|
nPort,
|
|
bstrUserName,
|
|
bstrPassword,
|
|
bBlockIncomingIPConnections,
|
|
bstrAltSymPath
|
|
);
|
|
FAILEDHR_BREAK(hr);
|
|
|
|
hr = HRESULT_FROM_WIN32(m_pEmSessThrd->Start());
|
|
FAILEDHR_BREAK(hr);
|
|
|
|
WaitForSingleObject( m_pEmSessThrd->m_hCDBStarted, INFINITE );
|
|
|
|
}
|
|
while( false );
|
|
}
|
|
__except ( EXCEPTION_EXECUTE_HANDLER, 1 ) {
|
|
|
|
hr = E_UNEXPECTED;
|
|
_ASSERTE( false );
|
|
}
|
|
|
|
m_pcs->ReadUnlock();
|
|
|
|
return hr;
|
|
}
|
|
|
|
STDMETHODIMP
|
|
CEmDebugSession::Debug
|
|
(
|
|
IN OUT BSTR bstrEmObj,
|
|
IN SessionType eSessType
|
|
)
|
|
{
|
|
return E_NOTIMPL;
|
|
}
|
|
|
|
STDMETHODIMP CEmDebugSession::CancelDebug(BOOL bForceCancel)
|
|
{
|
|
ATLTRACE(_T("CEmDebugSession::CancelDebug\n"));
|
|
|
|
HRESULT hr = E_FAIL;
|
|
LONG lStatus = 0L;
|
|
|
|
m_pcs->ReadLock();
|
|
|
|
__try {
|
|
|
|
hr = m_pASTManager->GetSessionStatus( m_pEmObj->guidstream, &lStatus );
|
|
if( FAILED(hr) ) { return hr; }
|
|
|
|
if( !(lStatus & STAT_SESS_DEBUG_IN_PROGRESS ) ) {
|
|
|
|
return (hr = EMERROR_PROCESSNOTBEINGDEBUGGED);
|
|
}
|
|
|
|
hr = CanTakeOwnership();
|
|
|
|
if( bForceCancel && hr == EMERROR_SESSIONORPHANED ) {
|
|
|
|
hr = m_pASTManager->AdoptThisSession( m_pEmObj->guidstream );
|
|
if( SUCCEEDED(hr) ) { SetMyselfAsMaster(); hr = S_OK; }
|
|
}
|
|
|
|
if( hr == S_OK ) { hr = m_pEmSessThrd->CancelDebugging(); }
|
|
}
|
|
__except ( EXCEPTION_EXECUTE_HANDLER, 1 ) {
|
|
|
|
hr = E_UNEXPECTED;
|
|
_ASSERTE( false );
|
|
}
|
|
|
|
m_pcs->ReadUnlock();
|
|
|
|
return hr;
|
|
}
|
|
|
|
void CEmDebugSession::SetMyselfAsMaster(bool bMaster /* = true */)
|
|
{
|
|
m_bMaster = bMaster;
|
|
}
|
|
|
|
HRESULT CEmDebugSession::CanTakeOwnership()
|
|
{
|
|
HRESULT hr = E_FAIL,
|
|
hrStat = E_FAIL;
|
|
LONG lStatus = 0L;
|
|
|
|
m_pcs->ReadLock();
|
|
|
|
__try
|
|
{
|
|
|
|
do
|
|
{
|
|
m_pASTManager->GetSessionStatus( m_pEmObj->guidstream, &lStatus, &hrStat );
|
|
|
|
if( HIWORD(lStatus) < HIWORD(STAT_SESS_DEBUG_IN_PROGRESS) ) {
|
|
|
|
hr = EMERROR_PROCESSNOTBEINGDEBUGGED;
|
|
break;
|
|
}
|
|
|
|
// if I am the master, I can do anything to the session..
|
|
if( AmITheMaster() == true ) { hr = S_OK; break; }
|
|
|
|
hr = m_pASTManager->IsSessionOrphaned( m_pEmObj->guidstream );
|
|
if( FAILED(hr) ) { break; }
|
|
|
|
// am not the master and the session is orphaned..
|
|
if( hr == S_OK ) { hr = EMERROR_SESSIONORPHANED; break; }
|
|
|
|
// am not the master and the session is not orphaned..
|
|
hr = E_ACCESSDENIED;
|
|
|
|
}
|
|
while( false );
|
|
}
|
|
|
|
__except ( EXCEPTION_EXECUTE_HANDLER, 1 ) {
|
|
|
|
hr = E_UNEXPECTED;
|
|
_ASSERTE( false );
|
|
}
|
|
|
|
m_pcs->ReadUnlock();
|
|
|
|
return hr;
|
|
}
|
|
|
|
STDMETHODIMP CEmDebugSession::AdoptOrphan()
|
|
{
|
|
HRESULT hr = E_FAIL;
|
|
|
|
m_pcs->ReadLock();
|
|
|
|
__try
|
|
{
|
|
hr = CanTakeOwnership();
|
|
|
|
if( hr == EMERROR_SESSIONORPHANED ) {
|
|
|
|
hr = m_pASTManager->AdoptThisSession( m_pEmObj->guidstream );
|
|
if( SUCCEEDED(hr) ) { SetMyselfAsMaster(); hr = S_OK; }
|
|
}
|
|
}
|
|
|
|
__except ( EXCEPTION_EXECUTE_HANDLER, 1 ) {
|
|
|
|
hr = E_UNEXPECTED;
|
|
_ASSERTE( false );
|
|
}
|
|
|
|
m_pcs->ReadUnlock();
|
|
|
|
return hr;
|
|
} |