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.
 
 
 
 
 
 

536 lines
14 KiB

#include <engexts.h>
//----------------------------------------------------------------------------
//
// StaticEventCallbacks.
//
//----------------------------------------------------------------------------
class StaticEventCallbacks : public DebugBaseEventCallbacks
{
public:
// IUnknown.
STDMETHOD_(ULONG, AddRef)(THIS);
STDMETHOD_(ULONG, Release)(THIS);
};
STDMETHODIMP_(ULONG)
StaticEventCallbacks::AddRef(THIS)
{
// This class is designed to be static so
// there's no true refcount.
return 1;
}
STDMETHODIMP_(ULONG)
StaticEventCallbacks::Release(THIS)
{
// This class is designed to be static so
// there's no true refcount.
return 0;
}
//----------------------------------------------------------------------------
//
// ExcepCallbacks.
//
//----------------------------------------------------------------------------
class ExcepCallbacks : public StaticEventCallbacks
{
public:
ExcepCallbacks(void)
{
m_Client = NULL;
m_Control = NULL;
}
// IDebugEventCallbacks.
STDMETHOD(GetInterestMask)(THIS_
OUT PULONG Mask);
STDMETHOD(Exception)(THIS_
IN PEXCEPTION_RECORD64 Exception,
IN ULONG FirstChance);
HRESULT Initialize(PDEBUG_CLIENT Client)
{
HRESULT Status;
m_Client = Client;
m_Client->AddRef();
if ((Status = m_Client->QueryInterface(__uuidof(IDebugControl),
(void**)&m_Control)) == S_OK)
{
#if 0
// Turn off default breakin on breakpoint exceptions.
Status = m_Control->Execute(DEBUG_OUTCTL_ALL_CLIENTS,
"sxd bpe", DEBUG_EXECUTE_DEFAULT);
#endif
}
return Status;
}
void Uninitialize(void)
{
EXT_RELEASE(m_Control);
EXT_RELEASE(m_Client);
}
private:
PDEBUG_CLIENT m_Client;
PDEBUG_CONTROL m_Control;
};
STDMETHODIMP
ExcepCallbacks::GetInterestMask(
THIS_
OUT PULONG Mask
)
{
*Mask = DEBUG_EVENT_EXCEPTION;
return S_OK;
}
STDMETHODIMP
ExcepCallbacks::Exception(
THIS_
IN PEXCEPTION_RECORD64 Exception,
IN ULONG FirstChance
)
{
m_Control->Output(DEBUG_OUTPUT_NORMAL, "Exception %X at %p, chance %d\n",
Exception->ExceptionCode, Exception->ExceptionAddress,
FirstChance ? 1 : 2);
return DEBUG_STATUS_GO_HANDLED;
}
ExcepCallbacks g_ExcepCallbacks;
//----------------------------------------------------------------------------
//
// FnProfCallbacks.
//
//----------------------------------------------------------------------------
class FnProfCallbacks : public StaticEventCallbacks
{
public:
FnProfCallbacks(void)
{
m_Client = NULL;
m_Control = NULL;
}
// IDebugEventCallbacks.
STDMETHOD(GetInterestMask)(THIS_
OUT PULONG Mask);
STDMETHOD(Breakpoint)(THIS_
IN PDEBUG_BREAKPOINT Bp);
HRESULT Initialize(PDEBUG_CLIENT Client,
PDEBUG_CONTROL Control)
{
m_Hits = 0;
m_Client = Client;
m_Client->AddRef();
m_Control = Control;
m_Control->AddRef();
return S_OK;
}
void Uninitialize(void)
{
EXT_RELEASE(m_Control);
EXT_RELEASE(m_Client);
}
ULONG GetHits(void)
{
return m_Hits;
}
PDEBUG_CONTROL GetControl(void)
{
return m_Control;
}
private:
PDEBUG_CLIENT m_Client;
PDEBUG_CONTROL m_Control;
ULONG m_Hits;
};
STDMETHODIMP
FnProfCallbacks::GetInterestMask(THIS_
OUT PULONG Mask)
{
*Mask = DEBUG_EVENT_BREAKPOINT;
return S_OK;
}
STDMETHODIMP
FnProfCallbacks::Breakpoint(THIS_
IN PDEBUG_BREAKPOINT Bp)
{
PDEBUG_CLIENT Client;
HRESULT Status = DEBUG_STATUS_NO_CHANGE;
// If this is one of our profiling breakpoints
// record the function hit and continue on.
if (Bp->GetAdder(&Client) == S_OK) {
if (Client == m_Client) {
m_Hits++;
Status = DEBUG_STATUS_GO;
}
Client->Release();
}
Bp->Release();
return Status;
}
FnProfCallbacks g_FnProfCallbacks;
//----------------------------------------------------------------------------
//
// Extension entry points.
//
//----------------------------------------------------------------------------
extern "C" HRESULT CALLBACK
DebugExtensionInitialize(PULONG Version, PULONG Flags)
{
*Version = DEBUG_EXTENSION_VERSION(1, 0);
*Flags = 0;
return S_OK;
}
extern "C" void CALLBACK
DebugExtensionUninitialize(void)
{
g_ExcepCallbacks.Uninitialize();
g_FnProfCallbacks.Uninitialize();
}
const char* szHelp =
" usage: !vtsimea [-? | function | address]\n"
"\n"
" where: -? displays this help\n"
" function name of the function to simulate EA at\n"
" address address to simulate EA at\n"
"\n"
" Example:\n"
" !vtsimea nv4_disp!DrvBitBlt\n";
const char* szErrorPrefix =
" Error: ";
const char* szErrorSuffix =
" Use -? for help\n";
const char* szSuccess = "Success.\n";
HRESULT EncodeInfiniteLoopX86(ULONG64 Address)
{
// jmp -2
unsigned char JmpOnSelf[2] = {0xEB, 0xFE};
return g_ExtData->WriteVirtual(Address,
&JmpOnSelf,
sizeof(JmpOnSelf),
NULL);
}
HRESULT EncodeInfiniteLoopIA64(ULONG64 Address)
{
// nop.m 0
// nop.m 0
// br.cond.sptk.many +0;;
unsigned char JmpOnSelf[16] = {0x19, 0x00, 0x00, 0x00,
0x01, 0x00, 0x00, 0x00,
0x00, 0x02, 0x00, 0x00,
0x08, 0x00, 0x00, 0x40};
return g_ExtData->WriteVirtual(Address,
&JmpOnSelf,
sizeof(JmpOnSelf),
NULL);
}
HRESULT SimulateEA(ULONG64 Address[2])
{
HRESULT Status;
HRESULT BpAdded[2] = {-1, -1};
PDEBUG_BREAKPOINT Bp[2];
ULONG BpId[2];
ULONG BpSize;
unsigned uBpHit = 0xFF;
unsigned i, count;
ExtOut("Get CPU type ... ");
ULONG CpuType;
Status = g_ExtControl->GetEffectiveProcessorType(&CpuType);
if (Status != S_OK) {
ExtErr("Failure! Can't get CPU type\n");
goto CleanExit;
}
switch (CpuType) {
case IMAGE_FILE_MACHINE_I386: BpSize = 1; break;
case IMAGE_FILE_MACHINE_IA64: BpSize = 16; break;
default:
ExtErr("Failure! Invalid CPU type %d\n", CpuType);
goto CleanExit;
}
ExtOut(szSuccess);
count = 0;
for (i = 0; Address[i] && (i < 2); ++i) {
ExtOut("Set HW breakpoint at %I64lx ... ", Address[i]);
Status = BpAdded[i] = g_ExtControl->AddBreakpoint(DEBUG_BREAKPOINT_DATA,
DEBUG_ANY_ID,
&Bp[i]);
if ((Status != S_OK) ||
((Status = Bp[i]->SetDataParameters(BpSize, DEBUG_BREAK_EXECUTE)) != S_OK) ||
((Status = Bp[i]->SetOffset(Address[i])) != S_OK) ||
((Status = Bp[i]->GetId(&BpId[i])) != S_OK) ||
((Status = Bp[i]->AddFlags(DEBUG_BREAKPOINT_ENABLED)) != S_OK))
{
ExtOut("Failure!\n");
}
else {
++count;
}
ExtOut(szSuccess);
} // for
if (!count) {
ExtErr("Failure! Unable to set HW breakpoints\n");
goto CleanExit;
}
ExtOut("Continuing execution (until BP hit) ... ");
Status = g_ExtControl->SetExecutionStatus(DEBUG_STATUS_GO);
if (Status != S_OK) {
ExtOut("Failure\n");
goto CleanExit;
}
Status = g_ExtControl->WaitForEvent(DEBUG_WAIT_DEFAULT, INFINITE);
if (Status != S_OK) {
ExtErr("Failure! Call to WaitForEvent failed\n");
goto CleanExit;
}
ULONG EvType, ProcessId, ThreadId;
DEBUG_LAST_EVENT_INFO_BREAKPOINT BpInfo;
Status = g_ExtControl->GetLastEventInformation(&EvType,
&ProcessId,
&ThreadId,
&BpInfo,
sizeof(BpInfo),
0,0,0,0);
if ((Status != S_OK) ||
(EvType != DEBUG_EVENT_BREAKPOINT))
{
ExtErr("Failure! Unknown event during EA simulation\n");
goto CleanExit;
}
for (i = 0; Address[i] && (i < 2); ++i) {
if (BpInfo.Id == BpId[i]) {
uBpHit = i;
break;
}
}
if (uBpHit > 1) {
ExtErr("Failure! Unknown breakpoint hit during EA simulation\n");
goto CleanExit;
}
ExtOut("\n");
for (i = 0; Address[i] && (i < 2); ++i) {
ExtOut("Disable HW breakpoint %d ... ", BpId[i]);
Status = Bp[i]->RemoveFlags(DEBUG_BREAKPOINT_ENABLED);
if (Status != S_OK) {
ExtOut("Failure\n");
goto CleanExit;
}
ExtOut(szSuccess);
}
ExtOut("Encoding infinite loop at %I64lx ... ", Address[uBpHit]);
switch (CpuType) {
case IMAGE_FILE_MACHINE_I386:
Status = EncodeInfiniteLoopX86(Address[uBpHit]);
break;
case IMAGE_FILE_MACHINE_IA64:
Status = EncodeInfiniteLoopIA64(Address[uBpHit]);
break;
}
if (Status != S_OK) {
ExtOut("Failure\n");
goto CleanExit;
}
ExtOut(szSuccess);
ExtOut("Continue execution until EA fault ...\n");
Status = g_ExtControl->SetExecutionStatus(DEBUG_STATUS_GO);
if (Status != S_OK) {
ExtOut("Failure\n");
goto CleanExit;
}
CleanExit:
for (i = 0; Address[i] && (i < 2); ++i) {
if (BpAdded[i] == S_OK) g_ExtControl->RemoveBreakpoint(Bp[i]);
}
return Status;
}
HRESULT GetAddressPair(PCSTR Args,
ULONG64 Address[2],
size_t* pCount)
{
HRESULT Status;
ULONG64 h;
Address[0] = Address[1] = 0;
*pCount = 0;
//
// Symbol can't start from number so we can optimize
// our resolution process
//
if ((Args[0] < '0') || (Args[0] > '9')) { // Guess it is just symbol
//
// search at least 2 to cover ia64 p-label
//
Status = g_ExtSymbols->StartSymbolMatch(Args, &h);
if (Status != S_OK) return Status;
char szName[1024];
ULONG64 Offset;
for(;;) {
Status = g_ExtSymbols->GetNextSymbolMatch(h,
szName,
sizeof(szName),
NULL,
&Offset);
if (Status != S_OK) break;
if (*pCount < 2) Address[*pCount] = Offset;
++*pCount;
}
g_ExtSymbols->EndSymbolMatch(h);
} // if
if (!*pCount) { // It is not simple symbol - guess it is expression
DEBUG_VALUE AddrVal;
Status = g_ExtControl->Evaluate(Args, DEBUG_VALUE_INT64, &AddrVal, NULL);
if (Status == S_OK) {
Address[0] = AddrVal.I64;
*pCount = 1;
}
} // if
if (!*pCount) return Status;
return Address[0] ? S_OK : -1;
}
extern "C" HRESULT CALLBACK
vtsimea(PDEBUG_CLIENT pClient, PCSTR Args)
{
HRESULT Status;
Status = ExtQuery(pClient);
if (Status != S_OK) {
ExtErr("Failure! Client unavailable\n");
return Status;
}
if (!g_ExtControl ||
!g_ExtData ||
!g_ExtSymbols)
{
ExtErr(szErrorPrefix);
ExtErr("Failure! Required interfaces are unavailable\n");
ExtRelease();
return -1;
}
size_t ArgsLen = Args ? strlen(Args) : 0;
if (!ArgsLen) {
ExtErr(szErrorSuffix);
}
if (ArgsLen >= 64) {
ExtErr(szErrorPrefix);
ExtErr("Parameters size too big\n");
ExtErr(szErrorSuffix);
}
else if (!strcmp(Args, "-?")) {
ExtOut(szHelp);
}
else if (strchr(Args, '*') ||
strchr(Args, '?') ||
strchr(Args, ' '))
{
ExtErr(szErrorPrefix);
ExtErr("Invalid parameter or wrong parameters number\n");
ExtErr(szErrorSuffix);
}
else {
size_t Count;
ULONG64 Address[2];
Status = GetAddressPair(Args, Address, &Count);
if (Status != S_OK) {
ExtErr(szErrorPrefix);
ExtErr("Can't resolve %s\n", Args);
ExtErr(szErrorSuffix);
}
else if (Count > 2) {
ExtErr(szErrorPrefix);
ExtErr("Too many resolutions for %s\n", Args);
ExtErr(szErrorSuffix);
}
else {
ExtOut("Simulating fault EA at %s (%I64lx)\n", Args, Address[0]);
Status = SimulateEA(Address);
}
}
ExtRelease();
return Status;
}
extern "C" HRESULT CALLBACK
simea(PDEBUG_CLIENT pClient, PCSTR Args)
{
return vtsimea(pClient, Args);
}