Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

550 lines
16 KiB

/*++
Copyright (c) 2000 Microsoft Corporation
Module Name:
event.cxx
Abstract:
This file contains the routines to track and handle
debugger events.
Author:
Jason Hartman (JasonHa) 2000-11-20
Environment:
User Mode
--*/
#include "precomp.hxx"
BOOL gbSymbolsNotLoaded = TRUE;
ULONG UniqueTargetState = INVALID_UNIQUE_STATE;
#if DBG && 0
ULONG
DbgEventPrint(
IN PCHAR Format,
...
)
{
va_list arglist;
va_start(arglist, Format);
return vDbgPrintExWithPrefix("Event: ", -1, 0, Format, arglist);
}
#else
#define DbgEventPrint
#endif
typedef struct {
PDEBUG_CLIENT Client;
BOOL ParamsRead;
} MonitorThreadParams;
DWORD WINAPI EventMonitorThread(MonitorThreadParams *);
class EventMonitorCallbacks : public DebugBaseEventCallbacks
{
private:
ULONG RefCount;
public:
EventMonitorCallbacks()
{
RefCount = 1;
}
// IUnknown
STDMETHOD_(ULONG, AddRef)(
THIS
)
{
RefCount++;
return RefCount;
}
STDMETHOD_(ULONG, Release)(
THIS
)
{
RefCount--;
if (RefCount == 0)
{
delete this;
return 0;
}
return RefCount;
}
// IDebugEventCallbacks.
STDMETHOD(GetInterestMask)(
THIS_
OUT PULONG Mask
)
{
DbgEventPrint("GetInterestMask\n");
if (Mask != NULL)
{
*Mask = DEBUG_EVENT_SESSION_STATUS |
DEBUG_EVENT_CHANGE_DEBUGGEE_STATE |
DEBUG_EVENT_CHANGE_ENGINE_STATE |
DEBUG_EVENT_CHANGE_SYMBOL_STATE |
DEBUG_EVENT_UNLOAD_MODULE;
}
return S_OK;
}
STDMETHOD(Breakpoint)(
THIS_
IN PDEBUG_BREAKPOINT Bp
)
{
DbgEventPrint("BP\n");
return DEBUG_STATUS_NO_CHANGE;
}
STDMETHOD(Exception)(
THIS_
IN PEXCEPTION_RECORD64 Exception,
IN ULONG FirstChance
)
{
DbgEventPrint("Exception\n");
return DEBUG_STATUS_NO_CHANGE;
}
STDMETHOD(CreateThread)(
THIS_
IN ULONG64 Handle,
IN ULONG64 DataOffset,
IN ULONG64 StartOffset
)
{
DbgEventPrint("CreateThread\n");
return DEBUG_STATUS_NO_CHANGE;
}
STDMETHOD(ExitThread)(
THIS_
IN ULONG ExitCode
)
{
DbgEventPrint("ExitThread\n");
return DEBUG_STATUS_NO_CHANGE;
}
STDMETHOD(CreateProcess)(
THIS_
IN ULONG64 ImageFileHandle,
IN ULONG64 Handle,
IN ULONG64 BaseOffset,
IN ULONG ModuleSize,
IN PCSTR ModuleName,
IN PCSTR ImageName,
IN ULONG CheckSum,
IN ULONG TimeDateStamp,
IN ULONG64 InitialThreadHandle,
IN ULONG64 ThreadDataOffset,
IN ULONG64 StartOffset
)
{
DbgEventPrint("CreateProcess\n");
return DEBUG_STATUS_NO_CHANGE;
}
STDMETHOD(ExitProcess)(
THIS_
IN ULONG ExitCode
)
{
DbgEventPrint("ExitProcess\n");
return DEBUG_STATUS_NO_CHANGE;
}
STDMETHOD(LoadModule)(
THIS_
IN ULONG64 ImageFileHandle,
IN ULONG64 BaseOffset,
IN ULONG ModuleSize,
IN PCSTR ModuleName,
IN PCSTR ImageName,
IN ULONG CheckSum,
IN ULONG TimeDateStamp
)
{
DbgEventPrint("LoadModule:\n"
" ModuleName: %s\n"
" ImageName: %s\n"
" BaseOffset: %I64x\n",
ModuleName, ImageName, BaseOffset);
return DEBUG_STATUS_NO_CHANGE;
}
STDMETHOD(UnloadModule)(
THIS_
IN PCSTR ImageBaseName,
IN ULONG64 BaseOffset
)
{
// Don't use Image base name for now - Debugger bug
//DbgEventPrint("UnloadModule %s @ %I64x\n", ImageBaseName, BaseOffset);
DbgEventPrint("UnloadModule ? @ %I64x\n", BaseOffset);
return DEBUG_STATUS_NO_CHANGE;
}
STDMETHOD(SystemError)(
THIS_
IN ULONG Error,
IN ULONG Level
)
{
DbgEventPrint("SystemError(%lu, %lu)\n", Error, Level);
return DEBUG_STATUS_NO_CHANGE;
}
STDMETHOD(SessionStatus)(
THIS_
IN ULONG Status
)
{
DbgEventPrint("SessionStatus(%lu)\n", Status);
if (Status == DEBUG_SESSION_ACTIVE) DbgEventPrint("DEBUG_SESSION_ACTIVE\n");
if (Status == DEBUG_SESSION_END_SESSION_ACTIVE_TERMINATE) DbgEventPrint("DEBUG_SESSION_END_SESSION_ACTIVE_TERMINATE\n");
if (Status == DEBUG_SESSION_END_SESSION_ACTIVE_DETACH) DbgEventPrint("DEBUG_SESSION_END_SESSION_ACTIVE_DETACH\n");
if (Status == DEBUG_SESSION_END_SESSION_PASSIVE) DbgEventPrint("DEBUG_SESSION_END_SESSION_PASSIVE\n");
if (Status == DEBUG_SESSION_END) DbgEventPrint("DEBUG_SESSION_END\n");
if (Status == DEBUG_SESSION_REBOOT) DbgEventPrint("DEBUG_SESSION_REBOOT\n");
if (Status == DEBUG_SESSION_HIBERNATE) DbgEventPrint("DEBUG_SESSION_HIBERNATE\n");
if (Status == DEBUG_SESSION_FAILURE) DbgEventPrint("DEBUG_SESSION_FAILURE\n");
return DEBUG_STATUS_NO_CHANGE;
}
STDMETHOD(ChangeDebuggeeState)(
THIS_
IN ULONG Flags,
IN ULONG64 Argument
)
{
DbgEventPrint("ChangeDebuggeeState(0x%lx, 0x%I64x)\n", Flags, Argument);
if (Flags == DEBUG_CDS_ALL)
{
DbgEventPrint("DEBUG_CDS_ALL\n");
UniqueTargetState++;
}
else
{
if (Flags & DEBUG_CDS_REGISTERS) DbgEventPrint("DEBUG_CDS_REGISTERS\n");
if (Flags & DEBUG_CDS_DATA)
{
DbgEventPrint("DEBUG_CDS_DATA\n");
UniqueTargetState++;
}
}
if (UniqueTargetState==INVALID_UNIQUE_STATE) UniqueTargetState++;
return S_OK;
}
STDMETHOD(ChangeEngineState)(
THIS_
IN ULONG Flags,
IN ULONG64 Argument
)
{
//DbgEventPrint("ChangeEngineState(0x%lx, 0x%I64x)\n", Flags, Argument);
if (Flags == DEBUG_CES_ALL)
{
DbgEventPrint("DEBUG_CES_ALL\n");
UniqueTargetState++;
if (UniqueTargetState==INVALID_UNIQUE_STATE) UniqueTargetState++;
}
else
{
if (Flags & DEBUG_CES_CURRENT_THREAD) DbgEventPrint("DEBUG_CES_CURRENT_THREAD\n");
if (Flags & DEBUG_CES_EFFECTIVE_PROCESSOR) DbgEventPrint("DEBUG_CES_EFFECTIVE_PROCESSOR\n");
if (Flags & DEBUG_CES_BREAKPOINTS) DbgEventPrint("DEBUG_CES_BREAKPOINTS\n");
if (Flags & DEBUG_CES_CODE_LEVEL) DbgEventPrint("DEBUG_CES_CODE_LEVEL\n");
if (Flags & DEBUG_CES_EXECUTION_STATUS)
{
DbgEventPrint("DEBUG_CES_EXECUTION_STATUS\n");
switch (Argument & DEBUG_STATUS_MASK)
{
case DEBUG_STATUS_NO_CHANGE: DbgPrint("Exec Status: DEBUG_STATUS_NO_CHANGE\n"); break;
case DEBUG_STATUS_GO: DbgPrint("Exec Status: DEBUG_STATUS_GO\n"); break;
case DEBUG_STATUS_GO_HANDLED: DbgPrint("Exec Status: DEBUG_STATUS_GO_HANDLED\n"); break;
case DEBUG_STATUS_GO_NOT_HANDLED: DbgPrint("Exec Status: DEBUG_STATUS_GO_NOT_HANDLED\n"); break;
case DEBUG_STATUS_STEP_OVER: DbgPrint("Exec Status: DEBUG_STATUS_STEP_OVER\n"); break;
case DEBUG_STATUS_STEP_INTO: DbgPrint("Exec Status: DEBUG_STATUS_STEP_INTO\n"); break;
case DEBUG_STATUS_BREAK: DbgPrint("Exec Status: DEBUG_STATUS_BREAK\n"); break;
case DEBUG_STATUS_NO_DEBUGGEE: DbgPrint("Exec Status: DEBUG_STATUS_NO_DEBUGGEE\n"); break;
case DEBUG_STATUS_STEP_BRANCH: DbgPrint("Exec Status: DEBUG_STATUS_STEP_BRANCH\n"); break;
case DEBUG_STATUS_IGNORE_EVENT: DbgPrint("Exec Status: DEBUG_STATUS_IGNORE_EVENT\n"); break;
default: DbgPrint("Exec Status: Unknown\n"); break;
}
if (Argument & DEBUG_STATUS_INSIDE_WAIT) DbgPrint("Exec Status: DEBUG_STATUS_INSIDE_WAIT\n");
if ((Argument & DEBUG_STATUS_MASK) != DEBUG_STATUS_NO_CHANGE)
{
UniqueTargetState++;
if (UniqueTargetState==INVALID_UNIQUE_STATE) UniqueTargetState++;
}
}
if (Flags & DEBUG_CES_ENGINE_OPTIONS) DbgEventPrint("DEBUG_CES_ENGINE_OPTIONS\n");
if (Flags & DEBUG_CES_LOG_FILE) DbgEventPrint("DEBUG_CES_LOG_FILE\n");
//if (Flags & DEBUG_CES_RADIX) DbgEventPrint("DEBUG_CES_RADIX\n");
if (Flags & DEBUG_CES_EVENT_FILTERS) DbgEventPrint("DEBUG_CES_EVENT_FILTERS\n");
if (Flags & DEBUG_CES_PROCESS_OPTIONS) DbgEventPrint("DEBUG_CES_PROCESS_OPTIONS\n");
if (Flags & DEBUG_CES_EXTENSIONS) DbgEventPrint("DEBUG_CES_EXTENSIONS\n");
}
return S_OK;
}
STDMETHOD(ChangeSymbolState)(
THIS_
IN ULONG Flags,
IN ULONG64 Argument
)
{
DbgEventPrint("ChangeSymbolState(0x%lx, 0x%I64x)\n", Flags, Argument);
gbSymbolsNotLoaded = gbSymbolsNotLoaded || (Flags & DEBUG_CSS_UNLOADS);
UniqueTargetState++;
if (UniqueTargetState==INVALID_UNIQUE_STATE) UniqueTargetState++;
return S_OK;
}
};
typedef enum {
NO_DISPATCHING,
NEED_DISPATCH,
DISPATCHED
} MonitorState;
LONG g_MonitorState = NO_DISPATCHING;
PDEBUG_CLIENT g_pMonitorClient = NULL;
BOOL g_MonitorThreadSet = FALSE;
DWORD
WINAPI
EventMonitorThread(
MonitorThreadParams *Params
)
{
HRESULT hr = S_OK;
PDEBUG_CLIENT Client;
MonitorThreadParams ParamCopy;
HMODULE hModule = NULL;
TCHAR ModulePath[256];
if (Params != NULL && Params->Client != NULL)
{
ASSERTMSG("EventMonitorThread not started with NEED_DISPATCH.\n", g_MonitorState == NEED_DISPATCH);
if (GetModuleFileName(ghDllInst, ModulePath, sizeof(ModulePath)/sizeof(TCHAR)) == 0)
{
DbgPrint("EventMonitorThread failed to get Module path.\n");
hr = S_FALSE;
}
else
{
// LoadLibrary so we have a reference while this thread lives
hModule = LoadLibrary(ModulePath);
if (hModule != ghDllInst)
{
DbgPrint("EventMonitorThread retrieving an hModule different from ghDllInst.\n");
hr = S_FALSE;
}
}
if (hr == S_OK)
{
Params->Client->AddRef();
ParamCopy = *Params;
Params->ParamsRead = TRUE;
Params = &ParamCopy;
hr = Params->Client->CreateClient(&Client);
DbgPrint("EventMonitorThread created client %p.\n", Client);
Params->Client->Release();
if (hr == S_OK)
{
EventMonitorCallbacks *EventMonitor = new EventMonitorCallbacks;
if (EventMonitor != NULL)
{
hr = Client->SetEventCallbacks(EventMonitor);
if (hr == S_OK)
{
// Pass monitoring client back to caller.
Client->AddRef();
if (InterlockedCompareExchangePointer((PVOID*)&g_pMonitorClient, Client, NULL) == NULL &&
InterlockedCompareExchange(&g_MonitorState, DISPATCHED, NEED_DISPATCH) == NEED_DISPATCH)
{
DbgPrint("EventMonitorThread dispatching for client %p.\n", Client);
UniqueTargetState++;
hr = Client->DispatchCallbacks(INFINITE);
}
else
{
// Another EventMonitorThread has already started or
// ReleaseEventCallbacks has already been called; so,
// release this client and
// NULL global monitor client if we set it
DbgPrint("EventMonitorThread exiting instead of dispatching for client %p.\n", Client);
InterlockedCompareExchangePointer((PVOID*)&g_pMonitorClient, NULL, Client);
Client->Release();
}
}
else
{
OutputControl OutCtl(Client);
OutCtl.OutErr("EventMonitorThread callbacks setup failed, %s.\n", pszHRESULT(hr));
}
EventMonitor->Release();
}
else
{
hr = E_OUTOFMEMORY;
}
Client->Release();
}
}
}
else
{
hr = E_INVALIDARG;
}
DbgPrint("EventMonitorThread calling ExitThread().\n");
FreeLibraryAndExitThread(hModule, (DWORD)hr);
}
void
ReleaseEventCallbacks(
PDEBUG_CLIENT Client
)
{
if (g_MonitorThreadSet)
{
if (InterlockedExchange(&g_MonitorState, NO_DISPATCHING) == DISPATCHED)
{
PDEBUG_CLIENT pMonitorClient;
pMonitorClient = (PDEBUG_CLIENT)InterlockedExchangePointer((PVOID *)&g_pMonitorClient, NULL);
ASSERTMSG("g_MonitorState shows g_pMonitorClient should be set.\n", pMonitorClient != NULL);
if (Client == NULL)
{
if (GetDebugClient(&Client) != S_OK)
{
Client = pMonitorClient;
Client->AddRef();
}
}
else
{
Client->AddRef();
}
Client->ExitDispatch(pMonitorClient);
pMonitorClient->Release();
Client->Release();
}
g_MonitorThreadSet = FALSE;
}
}
HRESULT
SetEventCallbacks(
PDEBUG_CLIENT Client
)
{
HRESULT hr = S_FALSE;
if (!g_MonitorThreadSet)
{
MonitorThreadParams NewThreadParams = { Client, FALSE };
HANDLE hThread;
DWORD ThreadID;
LONG PrevMonitorState;
PrevMonitorState = InterlockedExchange(&g_MonitorState, NEED_DISPATCH);
ASSERTMSG("Previous EventMonitor thread was never shutdown properly.\n", PrevMonitorState != DISPATCHED);
ASSERTMSG("Previous EventMonitor thread never completed setup.\n", PrevMonitorState != NEED_DISPATCH);
g_pMonitorClient = NULL;
hThread = CreateThread(NULL,
0,
(LPTHREAD_START_ROUTINE)EventMonitorThread,
&NewThreadParams,
0,
&ThreadID);
if (hThread)
{
// Default ExitCode to STILL_ACTIVE since it doesn't matter
// if the Params were read before we started checking.
DWORD ExitCode = STILL_ACTIVE;
while (!NewThreadParams.ParamsRead)
{
ExitCode = 0;
if (!GetExitCodeThread(hThread, &ExitCode))
DbgPrint("GetExitCodeThread returned error %lx.\n", GetLastError());
if (ExitCode != STILL_ACTIVE)
{
break;
}
SleepEx(10, TRUE);
}
if (ExitCode == STILL_ACTIVE)
{
hr = S_OK;
g_MonitorThreadSet = TRUE;
}
CloseHandle(hThread);
}
}
return hr;
}
HRESULT
EventCallbacksReady(
PDEBUG_CLIENT Client
)
{
return (g_MonitorThreadSet && g_MonitorState == DISPATCHED) ? S_OK : S_FALSE;
}