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