windows-nt/Source/XPSP1/NT/sdktools/debuggers/excepmon/emsvc/emdebugsession.cpp
2020-09-26 16:20:57 +08:00

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;
}