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.
 
 
 
 
 
 

300 lines
7.2 KiB

//----------------------------------------------------------------------------
//
// Example of how to connect to a debugger server and execute
// a command when the server is broken in.
//
// Copyright (C) Microsoft Corporation, 2002.
//
//----------------------------------------------------------------------------
#include <stdlib.h>
#include <stdio.h>
#include <stdarg.h>
#include <windows.h>
#include <dbgeng.h>
BOOL g_ForceBreak;
PSTR g_Connect;
PSTR g_Command = ".echo Broken in";
IDebugClient* g_Client;
IDebugClient* g_ExitDispatchClient;
IDebugControl* g_Control;
ULONG g_ExecStatus;
//----------------------------------------------------------------------------
//
// Event callbacks.
//
//----------------------------------------------------------------------------
class EventCallbacks : public DebugBaseEventCallbacks
{
public:
// IUnknown.
STDMETHOD_(ULONG, AddRef)(
THIS
);
STDMETHOD_(ULONG, Release)(
THIS
);
// IDebugEventCallbacks.
STDMETHOD(GetInterestMask)(
THIS_
OUT PULONG Mask
);
STDMETHOD(ChangeEngineState)(
THIS_
IN ULONG Flags,
IN ULONG64 Argument
);
};
STDMETHODIMP_(ULONG)
EventCallbacks::AddRef(
THIS
)
{
// This class is designed to be static so
// there's no true refcount.
return 1;
}
STDMETHODIMP_(ULONG)
EventCallbacks::Release(
THIS
)
{
// This class is designed to be static so
// there's no true refcount.
return 0;
}
STDMETHODIMP
EventCallbacks::GetInterestMask(
THIS_
OUT PULONG Mask
)
{
*Mask = DEBUG_EVENT_CHANGE_ENGINE_STATE;
return S_OK;
}
STDMETHODIMP
EventCallbacks::ChangeEngineState(
THIS_
IN ULONG Flags,
IN ULONG64 Argument
)
{
if (Flags & DEBUG_CES_EXECUTION_STATUS)
{
g_ExecStatus = (ULONG)Argument;
// If this notification came from a wait completing
// we want to wake up the input thread so that new
// commands can be processed. If it came from inside
// a wait we don't want to ask for input as the engine
// may go back to running at any time.
if (!(Argument & DEBUG_STATUS_INSIDE_WAIT))
{
// Wake up the wait loop.
g_ExitDispatchClient->ExitDispatch(g_Client);
}
}
return S_OK;
}
EventCallbacks g_EventCb;
//----------------------------------------------------------------------------
//
// Functions.
//
//----------------------------------------------------------------------------
void
Exit(int Code, PCSTR Format, ...)
{
// Clean up any resources.
if (g_Control != NULL)
{
g_Control->Release();
}
if (g_ExitDispatchClient != NULL)
{
g_ExitDispatchClient->Release();
}
if (g_Client != NULL)
{
g_Client->EndSession(DEBUG_END_DISCONNECT);
g_Client->Release();
}
// Output an error message if given.
if (Format != NULL)
{
va_list Args;
va_start(Args, Format);
vfprintf(stderr, Format, Args);
va_end(Args);
}
exit(Code);
}
void
CreateInterfaces(void)
{
HRESULT Status;
// Start things off by getting an initial interface from
// the engine. This can be any engine interface but is
// generally IDebugClient as the client interface is
// where sessions are started.
if ((Status = DebugConnect(g_Connect,
__uuidof(IDebugClient),
(void**)&g_Client)) != S_OK)
{
Exit(1, "DebugConnect(%s) failed, 0x%X\n",
g_Connect, Status);
}
// Query for some other interfaces that we'll need.
if ((Status = g_Client->QueryInterface(__uuidof(IDebugControl),
(void**)&g_Control)) != S_OK)
{
Exit(1, "QueryInterface failed, 0x%X\n", Status);
}
if ((Status = g_Client->SetEventCallbacks(&g_EventCb)) != S_OK)
{
Exit(1, "SetEventCallbacks failed, 0x%X\n", Status);
}
//
// This app may wait inside of a DispatchCallbacks
// while it's waiting for the server to break in.
// We'll need to be able to exit that dispatch so
// we need another connection to the server to
// send the exit request.
//
// This could all be avoided by simply doing a polling
// loop when waiting, but the intent of this sample
// is to show some of the more advanced callback-driven
// techniques.
//
if ((Status = DebugConnect(g_Connect,
__uuidof(IDebugClient),
(void**)&g_ExitDispatchClient)) != S_OK)
{
Exit(1, "DebugConnect(%s) failed, 0x%X\n",
g_Connect, Status);
}
}
void
ParseCommandLine(int Argc, char** Argv)
{
while (--Argc > 0)
{
Argv++;
if (!strcmp(*Argv, "-b"))
{
g_ForceBreak = TRUE;
}
else if (!strcmp(*Argv, "-cmd"))
{
if (Argc < 2)
{
Exit(1, "-cmd missing argument\n");
}
Argv++;
Argc--;
g_Command = *Argv;
}
else if (!strcmp(*Argv, "-remote"))
{
if (Argc < 2)
{
Exit(1, "-remote missing argument\n");
}
Argv++;
Argc--;
g_Connect = *Argv;
}
else
{
Exit(1, "Unknown command line argument '%s'\n", *Argv);
}
}
if (!g_Connect)
{
Exit(1, "No connection string specified, use -remote <options>\n");
}
}
void
WaitForBreakIn(void)
{
HRESULT Status;
// If we're forcing a break in request one.
if (g_ForceBreak)
{
if ((Status = g_Control->SetInterrupt(DEBUG_INTERRUPT_ACTIVE)) != S_OK)
{
Exit(1, "SetInterrupt failed, 0x%X\n", Status);
}
}
// Check on the current state as the server may be broken in.
if ((Status = g_Control->GetExecutionStatus(&g_ExecStatus)) != S_OK)
{
Exit(1, "GetExecutionStatus failed, 0x%X\n", Status);
}
printf("Waiting for break-in...\n");
while (g_ExecStatus != DEBUG_STATUS_BREAK)
{
// Wait for the server to enter the break-in state.
// When this happens our event callbacks will get called
// to update g_ExecStatus and wake up this wait.
if ((Status = g_Client->DispatchCallbacks(INFINITE)) != S_OK)
{
Exit(1, "DispatchCallbacks failed, 0x%X\n", Status);
}
}
// The server is broken in. Another user can immediately resume
// it but we'll assume that we're not competing with
// other server users.
}
void __cdecl
main(int Argc, char** Argv)
{
ParseCommandLine(Argc, Argv);
CreateInterfaces();
WaitForBreakIn();
printf("Executing '%s' on server\n", g_Command);
g_Control->Execute(DEBUG_OUTCTL_ALL_CLIENTS,
g_Command, DEBUG_EXECUTE_DEFAULT);
Exit(0, NULL);
}